mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-22 16:08:23 +08:00
Support for FTW blocks
- small UI fixes for EVSA - other minor stuff
This commit is contained in:
parent
57e24c7465
commit
1a6d2142b0
@ -176,7 +176,7 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|
|||||||
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;
|
||||||
}
|
}
|
||||||
|
@ -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('/', '_');
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
//
|
//
|
||||||
|
@ -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:
|
||||||
|
@ -47,6 +47,7 @@ namespace Types {
|
|||||||
NvramStoreFdc,
|
NvramStoreFdc,
|
||||||
NvramStoreFsys,
|
NvramStoreFsys,
|
||||||
NvramStoreEvsa,
|
NvramStoreEvsa,
|
||||||
|
NvramFtwBlock,
|
||||||
NvramVariableNvar,
|
NvramVariableNvar,
|
||||||
NvramVariableVss,
|
NvramVariableVss,
|
||||||
NvramVariableFsys,
|
NvramVariableFsys,
|
||||||
|
Loading…
Reference in New Issue
Block a user