Support for FTW blocks

- small UI fixes for EVSA
- other minor stuff
This commit is contained in:
Nikolaj Schlej 2016-04-08 13:22:18 +02:00
parent 57e24c7465
commit 1a6d2142b0
6 changed files with 239 additions and 36 deletions

View File

@ -176,7 +176,7 @@ void UEFITool::populateUi(const QModelIndex &current)
ui->menuFileActions->setEnabled(type == Types::File); ui->menuFileActions->setEnabled(type == Types::File);
ui->menuSectionActions->setEnabled(type == Types::Section); ui->menuSectionActions->setEnabled(type == Types::Section);
ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar || type == Types::NvramVariableVss || type == Types::NvramVariableFsys); ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar || type == Types::NvramVariableVss || type == Types::NvramVariableFsys);
ui->menuStoreActions->setEnabled(type == Types::NvramStoreVss || type == Types::NvramStoreFdc || type == Types::NvramStoreFsys || type == Types::NvramStoreEvsa); ui->menuStoreActions->setEnabled(type == Types::NvramStoreVss || type == Types::NvramStoreFdc || type == Types::NvramStoreFsys || type == Types::NvramStoreEvsa || type == Types::NvramFtwBlock);
// Enable actions // Enable actions
ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current)); ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current));
@ -553,6 +553,9 @@ void UEFITool::extract(const UINT8 mode)
case Types::NvramStoreEvsa: case Types::NvramStoreEvsa:
path = QFileDialog::getSaveFileName(this, tr("Save EVSA store to file"), name + ".evsa", "EVSA store files (*.evsa *.bin);;All files (*)"); path = QFileDialog::getSaveFileName(this, tr("Save EVSA store to file"), name + ".evsa", "EVSA store files (*.evsa *.bin);;All files (*)");
break; break;
case Types::NvramFtwBlock:
path = QFileDialog::getSaveFileName(this, tr("Save FTW block to file"), name + ".ftw", "FTW block files (*.ftw *.bin);;All files (*)");
break;
default: default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)"); path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
} }
@ -599,6 +602,9 @@ void UEFITool::extract(const UINT8 mode)
case Types::NvramStoreEvsa: case Types::NvramStoreEvsa:
path = QFileDialog::getSaveFileName(this, tr("Save EVSA store body to file"), name + ".esb", "EVSA store body files (*.esb *.bin);;All files (*)"); path = QFileDialog::getSaveFileName(this, tr("Save EVSA store body to file"), name + ".esb", "EVSA store body files (*.esb *.bin);;All files (*)");
break; break;
case Types::NvramFtwBlock:
path = QFileDialog::getSaveFileName(this, tr("Save FTW block body to file"), name + ".ftb", "FTW block body files (*.ftb *.bin);;All files (*)");
break;
default: default:
path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)"); path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)");
} }
@ -969,6 +975,7 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
case Types::NvramStoreFdc: case Types::NvramStoreFdc:
case Types::NvramStoreFsys: case Types::NvramStoreFsys:
case Types::NvramStoreEvsa: case Types::NvramStoreEvsa:
case Types::NvramFtwBlock:
ui->menuStoreActions->exec(event->globalPos()); ui->menuStoreActions->exec(event->globalPos());
break; break;
} }

View File

@ -76,6 +76,8 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr
case Types::NvramStoreVss: case Types::NvramStoreVss:
case Types::NvramStoreFdc: case Types::NvramStoreFdc:
case Types::NvramStoreFsys: case Types::NvramStoreFsys:
case Types::NvramStoreEvsa:
case Types::NvramFtwBlock:
default: default:
name = itemName.replace(' ', '_').replace('/', '_'); name = itemName.replace(' ', '_').replace('/', '_');
} }

View File

@ -1046,7 +1046,7 @@ STATUS FfsParser::parseVolumeHeader(const QByteArray & volume, const UINT32 pare
} }
// Check for VSS NVRAM volume // Check for VSS NVRAM volume
if (guid == NVRAM_VSS_STORE_VOLUME_GUID || guid == NVRAM_ADDITIONAL_STORE_VOLUME_GUID) { if (guid == NVRAM_MAIN_STORE_VOLUME_GUID || guid == NVRAM_ADDITIONAL_STORE_VOLUME_GUID) {
isUnknown = false; isUnknown = false;
isNvramVolume = true; isNvramVolume = true;
} }
@ -3200,12 +3200,10 @@ parsing_done:
msg(QObject::tr("parseNvarStore: extended data size (%1h) is smaller than required for timestamp and hash (0x28)") msg(QObject::tr("parseNvarStore: extended data size (%1h) is smaller than required for timestamp and hash (0x28)")
.hexarg(extendedData.size()), varIndex); .hexarg(extendedData.size()), varIndex);
// Check variable name to be in the list of nesting variables // Try parsing the variable data as NVAR storage if it begins with NVAR signature
if (text == QString("StdDefaults") || text == QString("MfgDefaults")) { if ((subtype == Subtypes::DataNvarVariable || subtype == Subtypes::FullNvarVariable) &&
STATUS result = parseNvarStore(body, varIndex); *(const UINT32*)body.constData() == NVRAM_NVAR_VARIABLE_SIGNATURE)
if (result) parseNvarStore(body, varIndex);
msg(QObject::tr("parseNvarStore: parsing of nested NVAR store failed with error \"%1\"").arg(errorCodeToQString(result)), varIndex);
}
// Move to next variable // Move to next variable
offset += variableHeader->Size; offset += variableHeader->Size;
@ -3281,16 +3279,10 @@ STATUS FfsParser::parseStoreArea(const QByteArray & data, const QModelIndex & in
return result; return result;
} }
// Check that store is fully present in input // Check that current store is fully present in input
if (storeSize > (UINT32)data.size() || storeOffset + storeSize > (UINT32)data.size()) { if (storeSize > (UINT32)data.size() || storeOffset + storeSize > (UINT32)data.size()) {
msg(QObject::tr("parseVssStoreArea: one of stores inside overlaps the end of data"), index);
return ERR_INVALID_VOLUME;
}
QByteArray store = data.mid(storeOffset, storeSize);
if (storeSize > (UINT32)store.size()) {
// Mark the rest as padding and finish the parsing // Mark the rest as padding and finish the parsing
QByteArray padding = data.right(store.size()); QByteArray padding = data.mid(storeOffset);
// Get info // Get info
name = QObject::tr("Padding"); name = QObject::tr("Padding");
@ -3310,6 +3302,7 @@ STATUS FfsParser::parseStoreArea(const QByteArray & data, const QModelIndex & in
break; break;
} }
QByteArray store = data.mid(storeOffset, storeSize);
// Parse current volume's header // Parse current volume's header
QModelIndex storeIndex; QModelIndex storeIndex;
result = parseStoreHeader(store, parentOffset + storeOffset, index, storeIndex); result = parseStoreHeader(store, parentOffset + storeOffset, index, storeIndex);
@ -3373,6 +3366,7 @@ STATUS FfsParser::parseStoreArea(const QByteArray & data, const QModelIndex & in
case Types::NvramStoreEvsa: case Types::NvramStoreEvsa:
parseEvsaStoreBody(current); parseEvsaStoreBody(current);
break; break;
case Types::NvramFtwBlock:
case Types::Padding: case Types::Padding:
// No parsing required // No parsing required
break; break;
@ -3404,34 +3398,70 @@ STATUS FfsParser::findNextStore(const QModelIndex & index, const QByteArray & da
msg(QObject::tr("findNextStore: VSS store candidate at offset %1h skipped, has invalid size %2h").hexarg(parentOffset + offset).hexarg2(vssHeader->Size, 8), index); msg(QObject::tr("findNextStore: VSS store candidate at offset %1h skipped, has invalid size %2h").hexarg(parentOffset + offset).hexarg2(vssHeader->Size, 8), index);
continue; continue;
} }
// All checks passed, store found // All checks passed, store found
break; break;
} }
else if (*currentPos == NVRAM_FDC_VOLUME_SIGNATURE) { //FDC signature found else if (*currentPos == NVRAM_FDC_VOLUME_SIGNATURE) { //FDC signature found
// No checks needed const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)currentPos;
if (fdcHeader->Size == 0 || fdcHeader->Size == 0xFFFFFFFF) {
msg(QObject::tr("findNextStore: FDC store candidate at offset %1h skipped, has invalid size %2h").hexarg(parentOffset + offset).hexarg2(fdcHeader->Size, 8), index);
continue;
}
// All checks passed, store found
break; break;
} }
else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { //Fsys signature found else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { //Fsys signature found
// No checks needed const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)currentPos;
if (fsysHeader->Size == 0 || fsysHeader->Size == 0xFFFF) {
msg(QObject::tr("findNextStore: Fsys store candidate at offset %1h skipped, has invalid size %2h").hexarg(parentOffset + offset).hexarg2(fsysHeader->Size, 4), index);
continue;
}
// All checks passed, store found
break; break;
} }
else if (*currentPos == NVRAM_EVSA_STORE_SIGNATURE) { //EVSA signature found else if (*currentPos == NVRAM_EVSA_STORE_SIGNATURE) { //EVSA signature found
if (offset < 4) if (offset < 4)
continue; continue;
const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)(currentPos - 1); const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)(currentPos - 1);
if (evsaHeader->Header.Type != NVRAM_EVSA_ENTRY_TYPE_STORE) { if (evsaHeader->Header.Type != NVRAM_EVSA_ENTRY_TYPE_STORE) {
msg(QObject::tr("findNextStore: EVSA store candidate at offset %1h skipped, has invalid type %2h").hexarg(parentOffset + offset - 4).hexarg2(evsaHeader->Header.Type, 2), index); msg(QObject::tr("findNextStore: EVSA store candidate at offset %1h skipped, has invalid type %2h").hexarg(parentOffset + offset - 4).hexarg2(evsaHeader->Header.Type, 2), index);
continue; continue;
} }
if (evsaHeader->StoreSize == 0 || evsaHeader->StoreSize == 0xFFFFFFFF) {
msg(QObject::tr("findNextStore: EVSA store candidate at offset %1h skipped, has invalid size %2h").hexarg(parentOffset + offset).hexarg2(evsaHeader->StoreSize, 8), index);
continue;
}
// All checks passed, store found // All checks passed, store found
offset -= 4; offset -= 4;
break; break;
} }
else if (*currentPos == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1) { //Possible FTW block signature found
if (QByteArray(data.constData() + offset, sizeof(EFI_GUID)) != NVRAM_MAIN_STORE_VOLUME_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
if (ftwHeader->WriteQueueSize == 0 || ftwHeader->WriteQueueSize == 0xFFFFFFFF) {
msg(QObject::tr("findNextStore: FTW block candidate at offset %1h skipped, has invalid body size %2h").hexarg(parentOffset + offset).hexarg2(ftwHeader->WriteQueueSize, 8), index);
continue;
}
}
else if (ftwHeader->WriteQueueSize % 0x10 == 0x00) { // Header with 64 bit WriteQueueSize
const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64Header = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)currentPos;
if (ftw64Header->WriteQueueSize == 0 || ftw64Header->WriteQueueSize >= 0xFFFFFFFF) {
msg(QObject::tr("findNextStore: FTW block candidate at offset %1h skipped, has invalid body size %2h").hexarg(parentOffset + offset).hexarg2(ftw64Header->WriteQueueSize, 16), index);
continue;
}
}
else // Unknown header
continue;
// All checks passed, store found
break;
}
} }
// No more storas found // No more stores found
if (offset >= dataSize - sizeof(UINT32)) if (offset >= dataSize - sizeof(UINT32))
return ERR_STORES_NOT_FOUND; return ERR_STORES_NOT_FOUND;
@ -3442,7 +3472,6 @@ STATUS FfsParser::findNextStore(const QModelIndex & index, const QByteArray & da
STATUS FfsParser::getStoreSize(const QByteArray & data, const UINT32 storeOffset, UINT32 & storeSize) STATUS FfsParser::getStoreSize(const QByteArray & data, const UINT32 storeOffset, UINT32 & storeSize)
{ {
//TODO: add GUID support
const UINT32* signature = (const UINT32*)(data.constData() + storeOffset); const UINT32* signature = (const UINT32*)(data.constData() + storeOffset);
if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) { if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) {
const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature; const VSS_VARIABLE_STORE_HEADER* vssHeader = (const VSS_VARIABLE_STORE_HEADER*)signature;
@ -3460,13 +3489,23 @@ STATUS FfsParser::getStoreSize(const QByteArray & data, const UINT32 storeOffset
const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)signature; const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)signature;
storeSize = evsaHeader->StoreSize; storeSize = evsaHeader->StoreSize;
} }
else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1) {
const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftwHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)signature;
if (ftwHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize
storeSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) + ftwHeader->WriteQueueSize;
}
else { // Header with 64 bit WriteQueueSize
const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64Header = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)signature;
storeSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64) + ftw64Header->WriteQueueSize;
}
}
return ERR_SUCCESS; return ERR_SUCCESS;
} }
STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index) STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{ {
// Parse VSS volume like raw area // Parse VSS volume like raw area
//TODO: seen for now - $VSS, $SVS, Fsys, full volume GUID, _FDC, EVSA and paddings //Seen for now: $VSS, $SVS, Fsys, FTW block, _FDC, EVSA, _FLASH_MAP and paddings
const UINT32 dataSize = (UINT32)store.size(); const UINT32 dataSize = (UINT32)store.size();
const UINT32* signature = (const UINT32*)store.constData(); const UINT32* signature = (const UINT32*)store.constData();
@ -3685,6 +3724,68 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent
// Add tree item // Add tree item
index = model->addItem(Types::NvramStoreEvsa, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent); index = model->addItem(Types::NvramStoreEvsa, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
} }
else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1) {
// The volume must begin with a store to be valid, but after the first one, there can be many variants
if (dataSize < sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64)) {
msg(QObject::tr("parseStoreHeader: volume body is too small even for FTW block header"), parent);
return ERR_SUCCESS;
}
// Get FTW block headers
const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* ftw32BlockHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)signature;
const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64* ftw64BlockHeader = (const EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64*)signature;
// Check store size
UINT32 ftwBlockSize;
bool has32bitHeader;
if (ftw32BlockHeader->WriteQueueSize % 0x10 == 0x04) { // Header with 32 bit WriteQueueSize
ftwBlockSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) + ftw32BlockHeader->WriteQueueSize;
has32bitHeader = true;
}
else { // Header with 64 bit WriteQueueSize
ftwBlockSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64) + ftw64BlockHeader->WriteQueueSize;
has32bitHeader = false;
}
if (dataSize < ftwBlockSize) {
msg(QObject::tr("parseStoreHeader: FTW block size %1h (%2) is greater than volume body size %3h (%4)")
.hexarg2(ftwBlockSize, 4).arg(ftwBlockSize)
.hexarg2(dataSize, 8).arg(dataSize), parent);
return ERR_SUCCESS;
}
// Get parsing data
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Construct header and body
UINT32 headerSize = has32bitHeader ? sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32) : sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64);
QByteArray header = store.left(headerSize);
QByteArray body = store.mid(headerSize, ftwBlockSize - headerSize);
// Check block header checksum
QByteArray crcHeader = header;
EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32* crcFtwBlockHeader = (EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32*)header.data();
crcFtwBlockHeader->Crc = pdata.emptyByte ? 0xFFFFFFFF : 0;
crcFtwBlockHeader->State = pdata.emptyByte ? 0xFF : 0;
UINT32 calculatedCrc = crc32(0, (const UINT8*)crcFtwBlockHeader, headerSize);
// Add info
QString name = QObject::tr("FTW block");
QString info = QObject::tr("Signature: %1\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nState: %8h\nHeader CRC32: %9")
.arg(guidToQString(ftw32BlockHeader->Signature))
.hexarg(ftwBlockSize).arg(ftwBlockSize)
.hexarg(headerSize).arg(headerSize)
.hexarg(body.size()).arg(body.size())
.hexarg2(ftw32BlockHeader->State, 2)
.arg(ftw32BlockHeader->Crc == calculatedCrc ?
QObject::tr("%1h, valid").hexarg2(ftw32BlockHeader->Crc, 8) :
QObject::tr("%1h, invalid, should be %2h").hexarg2(ftw32BlockHeader->Crc, 8).hexarg2(calculatedCrc, 8));
// Add correct offset
pdata.offset = parentOffset;
// Add tree item
index = model->addItem(Types::NvramFtwBlock, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent);
}
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -3972,7 +4073,7 @@ STATUS FfsParser::parseFsysStoreBody(const QModelIndex & index)
model->addItem(Types::Padding, getPaddingType(body), QObject::tr("Padding"), QString(), info, QByteArray(), body, FALSE, parsingDataToQByteArray(pdata), index); model->addItem(Types::Padding, getPaddingType(body), QObject::tr("Padding"), QString(), info, QByteArray(), body, FALSE, parsingDataToQByteArray(pdata), index);
// Show message // Show message
msg(QObject::tr("parseFsysStoreBody: variable appears too big, added as padding"), index); msg(QObject::tr("parseFsysStoreBody: next variable appears too big, added as padding"), index);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
@ -4015,11 +4116,13 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index)
const UINT32 dataSize = (UINT32)data.size(); const UINT32 dataSize = (UINT32)data.size();
UINT32 offset = 0; UINT32 offset = 0;
// Parse all variables std::map<UINT16, EFI_GUID> guidMap;
while (1) { std::map<UINT16, QString> nameMap;
UINT32 unparsedSize = dataSize - offset;
UINT32 variableSize = 0;
// Parse all variables
UINT32 unparsedSize = dataSize;
while (unparsedSize) {
UINT32 variableSize = 0;
QString name; QString name;
QString info; QString info;
QByteArray header; QByteArray header;
@ -4032,8 +4135,22 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index)
// Check variable size // Check variable size
variableSize = sizeof(EVSA_ENTRY_HEADER); variableSize = sizeof(EVSA_ENTRY_HEADER);
if (unparsedSize < variableSize || unparsedSize < entryHeader->Size) { if (unparsedSize < variableSize || unparsedSize < entryHeader->Size) {
//Add the rest as padding and break from cycle // Last variable is bad, add the rest as padding and return
return ERR_SUCCESS; QByteArray body = data.mid(offset);
QString info = QObject::tr("Full size: %1h (%2)")
.hexarg(body.size()).arg(body.size());
// Add correct offset to parsing data
pdata.offset = parentOffset + offset;
// Add free space tree item
model->addItem(Types::Padding, getPaddingType(body), QObject::tr("Padding"), QString(), info, QByteArray(), body, FALSE, parsingDataToQByteArray(pdata), index);
// Show message
if (unparsedSize < entryHeader->Size)
msg(QObject::tr("parseEvsaStoreBody: next variable appears too big, added as padding"), index);
break;
} }
variableSize = entryHeader->Size; variableSize = entryHeader->Size;
@ -4056,6 +4173,7 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index)
QObject::tr("%1h, invalid, should be %2h").hexarg2(guidHeader->Header.Checksum, 2).hexarg2(calculated, 2)) QObject::tr("%1h, invalid, should be %2h").hexarg2(guidHeader->Header.Checksum, 2).hexarg2(calculated, 2))
.hexarg2(guidHeader->GuidId, 4); .hexarg2(guidHeader->GuidId, 4);
subtype = Subtypes::GuidEvsaEntry; subtype = Subtypes::GuidEvsaEntry;
guidMap.insert_or_assign(guidHeader->GuidId, guidHeader->Guid);
} }
// Name entry // Name entry
else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME1 || else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME1 ||
@ -4074,6 +4192,7 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index)
QObject::tr("%1h, invalid, should be %2h").hexarg2(nameHeader->Header.Checksum, 2).hexarg2(calculated, 2)) QObject::tr("%1h, invalid, should be %2h").hexarg2(nameHeader->Header.Checksum, 2).hexarg2(calculated, 2))
.hexarg2(nameHeader->VarId, 4); .hexarg2(nameHeader->VarId, 4);
subtype = Subtypes::NameEvsaEntry; subtype = Subtypes::NameEvsaEntry;
nameMap.insert_or_assign(nameHeader->VarId, name);
} }
// Data entry // Data entry
else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA1 || else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_DATA1 ||
@ -4098,7 +4217,18 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index)
} }
// Unknown entry // Unknown entry
else { else {
; header = data.mid(offset, sizeof(EVSA_ENTRY_HEADER));
body = data.mid(offset + sizeof(EVSA_ENTRY_HEADER), entryHeader->Size - sizeof(EVSA_ENTRY_HEADER));
name = QObject::tr("Unknown");
info = QObject::tr("Full size: %1h (%2)\nHeader size %3h (%4)\nBody size: %5h (%6)\nType: %7h\nChecksum: %8")
.hexarg(variableSize).arg(variableSize)
.hexarg(header.size()).arg(header.size())
.hexarg(body.size()).arg(body.size())
.hexarg2(entryHeader->Type, 2)
.arg(entryHeader->Checksum == calculated ?
QObject::tr("%1h, valid").hexarg2(calculated, 2) :
QObject::tr("%1h, invalid, should be %2h").hexarg2(entryHeader->Checksum, 2).hexarg2(calculated, 2));
subtype = Subtypes::UnknownEvsaEntry;
} }
// Add correct offset to parsing data // Add correct offset to parsing data
@ -4109,9 +4239,44 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index)
// Move to next variable // Move to next variable
offset += variableSize; offset += variableSize;
unparsedSize = dataSize - 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++) {
QModelIndex current = index.child(i, 0);
if (model->subtype(current) == Subtypes::DataEvsaEntry) {
QByteArray header = model->header(current);
const EVSA_DATA_ENTRY* dataHeader = (const EVSA_DATA_ENTRY*)header.constData();
QString guid;
if (guidMap.count(dataHeader->GuidId))
guid = guidToQString(guidMap[dataHeader->GuidId]);
QString 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);
model->setName(current, QObject::tr("Invalid"));
msg(QObject::tr("parseEvsaStoreBody: data variable with invalid GuidId and invalid VarId"), current);
}
else if (guid.isEmpty()) { // Guid not found
model->setSubtype(current, Subtypes::InvalidEvsaEntry);
model->setName(current, QObject::tr("Invalid"));
msg(QObject::tr("parseEvsaStoreBody: data variable with invalid GuidId"), current);
}
else if (name.isEmpty()) { // Name not found
model->setSubtype(current, Subtypes::InvalidEvsaEntry);
model->setName(current, QObject::tr("Invalid"));
msg(QObject::tr("parseEvsaStoreBody: data variable with invalid VarId"), current);
}
else { // Variable is OK, rename it
model->setName(current, guid);
model->setText(current, name);
}
}
}
return ERR_SUCCESS; return ERR_SUCCESS;
} }

View File

@ -40,7 +40,7 @@ extern QString efiTimeToQString(const EFI_TIME & time);
// Variable header // Variable header
typedef struct _NVAR_VARIABLE_HEADER { typedef struct _NVAR_VARIABLE_HEADER {
UINT32 Signature; // NVAR signature UINT32 Signature; // NVAR
UINT16 Size; // Size of the variable including header UINT16 Size; // Size of the variable including header
UINT32 Next : 24; // Offset to the next variable in a list, or empty if latest in the list UINT32 Next : 24; // Offset to the next variable in a list, or empty if latest in the list
UINT32 Attributes : 8; // Attributes UINT32 Attributes : 8; // Attributes
@ -64,13 +64,16 @@ typedef struct _NVAR_VARIABLE_HEADER {
#define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_AUTH_WRITE 0x10 #define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_AUTH_WRITE 0x10
#define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_TIME_BASED 0x20 #define NVRAM_NVAR_VARIABLE_EXT_ATTRIB_TIME_BASED 0x20
// //
// TianoCore VSS and it's variations // TianoCore VSS and it's variations
// //
// FFF12B8D-7696-4C8B-A985-2747075B4F50 // FFF12B8D-7696-4C8B-A985-2747075B4F50
const QByteArray NVRAM_VSS_STORE_VOLUME_GUID const QByteArray NVRAM_MAIN_STORE_VOLUME_GUID
("\x8D\x2B\xF1\xFF\x96\x76\x8B\x4C\xA9\x85\x27\x47\x07\x5B\x4F\x50", 16); ("\x8D\x2B\xF1\xFF\x96\x76\x8B\x4C\xA9\x85\x27\x47\x07\x5B\x4F\x50", 16);
#define NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 0xFFF12B8D
// 00504624-8A59-4EEB-BD0F-6B36E96128E0 // 00504624-8A59-4EEB-BD0F-6B36E96128E0
const QByteArray NVRAM_ADDITIONAL_STORE_VOLUME_GUID const QByteArray NVRAM_ADDITIONAL_STORE_VOLUME_GUID
@ -168,6 +171,28 @@ typedef struct _FDC_VOLUME_HEADER {
//VSS_VARIABLE_STORE_HEADER VssHeader; //VSS_VARIABLE_STORE_HEADER VssHeader;
} FDC_VOLUME_HEADER; } FDC_VOLUME_HEADER;
// FTW block
// EFI Fault tolerant working block header
#define EFI_FAULT_TOLERANT_WORKING_BLOCK_VALID 0x1
#define EFI_FAULT_TOLERANT_WORKING_BLOCK_INVALID 0x2
typedef struct {
EFI_GUID Signature; // NVRAM_MAIN_STORE_VOLUME_GUID
UINT32 Crc; // Crc32 of the header with empty Crc and State fields
UINT8 State;
UINT8 Reserved3[3];
UINT32 WriteQueueSize; // Size of the FTW block without the header
//UINT8 WriteQueue[WriteQueueSize];
} EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32;
typedef struct {
EFI_GUID Signature; // NVRAM_MAIN_STORE_VOLUME_GUID
UINT32 Crc; // Crc32 of the header with empty Crc and State fields
UINT8 State;
UINT8 Reserved3[3];
UINT64 WriteQueueSize; // Size of the FTW block without the header
//UINT8 WriteQueue[WriteQueueSize];
} EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64;
// //
// Apple Fsys // Apple Fsys
// //

View File

@ -73,6 +73,8 @@ QString itemTypeToQString(const UINT8 type)
return QObject::tr("Fsys store"); return QObject::tr("Fsys store");
case Types::NvramStoreEvsa: case Types::NvramStoreEvsa:
return QObject::tr("EVSA store"); return QObject::tr("EVSA store");
case Types::NvramFtwBlock:
return QObject::tr("FTW block");
case Types::NvramVariableNvar: case Types::NvramVariableNvar:
return QObject::tr("NVAR variable"); return QObject::tr("NVAR variable");
case Types::NvramVariableVss: case Types::NvramVariableVss:
@ -140,6 +142,7 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype)
case Types::NvramStoreFdc: case Types::NvramStoreFdc:
case Types::NvramStoreFsys: case Types::NvramStoreFsys:
case Types::NvramStoreEvsa: case Types::NvramStoreEvsa:
case Types::NvramFtwBlock:
case Types::NvramVariableFsys: case Types::NvramVariableFsys:
return QString(); return QString();
case Types::NvramVariableNvar: case Types::NvramVariableNvar:

View File

@ -47,6 +47,7 @@ namespace Types {
NvramStoreFdc, NvramStoreFdc,
NvramStoreFsys, NvramStoreFsys,
NvramStoreEvsa, NvramStoreEvsa,
NvramFtwBlock,
NvramVariableNvar, NvramVariableNvar,
NvramVariableVss, NvramVariableVss,
NvramVariableFsys, NvramVariableFsys,