From 1100cead243088d43d8586e779265b00fdfb2da5 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Wed, 13 Apr 2016 01:35:18 +0200 Subject: [PATCH] UT NE A25 - support for Phoenix SCT FlashMap - support for Apple Gaid stores - UI for EVSA and FlashMap store and entries - small fixes --- UEFITool/uefitool.cpp | 49 ++++++++--- common/ffsops.cpp | 15 +--- common/ffsparser.cpp | 192 ++++++++++++++++++++++++++++++++++-------- common/ffsparser.h | 1 + common/nvram.h | 56 ++++++++++-- common/types.cpp | 18 ++-- common/types.h | 8 +- 7 files changed, 261 insertions(+), 78 deletions(-) diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp index ce6b8df..3e6cc08 100644 --- a/UEFITool/uefitool.cpp +++ b/UEFITool/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.30.0_alpha24")) +version(tr("0.30.0_alpha25")) { clipboard = QApplication::clipboard(); @@ -172,8 +172,10 @@ 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 || type == Types::NvramVariableVss || type == Types::NvramVariableFsys); - ui->menuStoreActions->setEnabled(type == Types::NvramStoreVss || type == Types::NvramStoreFdc || type == Types::NvramStoreFsys || type == Types::NvramStoreEvsa || type == Types::NvramFtwBlock); + ui->menuVariableActions->setEnabled(type == Types::NvramVariableNvar || type == Types::NvramVariableVss || type == Types::NvramEntryFsys + || type == Types::NvramEntryEvsa || type == Types::NvramEntryFlashMap); + ui->menuStoreActions->setEnabled(type == Types::NvramStoreVss || type == Types::NvramStoreFdc || type == Types::NvramStoreFsys + || type == Types::NvramStoreEvsa || type == Types::NvramStoreFtw || type == Types::NvramStoreFlashMap); // Enable actions ui->actionExtract->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current)); @@ -537,12 +539,25 @@ void UEFITool::extract(const UINT8 mode) 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; case Types::NvramVariableVss: - path = QFileDialog::getSaveFileName(this, tr("Save variable to file"), name + ".var", "Variable files (*.var *.bin);;All files (*)"); + path = QFileDialog::getSaveFileName(this, tr("Save VSS variable to file"), name + ".var", "VSS variable files (*.var *.bin);;All files (*)"); + break; + case Types::NvramEntryFsys: + path = QFileDialog::getSaveFileName(this, tr("Save Fsys entry to file"), name + ".fse", "Fsys entry files (*.fse *.bin);;All files (*)"); + break; + case Types::NvramEntryEvsa: + path = QFileDialog::getSaveFileName(this, tr("Save EVSA entry to file"), name + ".evse", "EVSA entry files (*.evse *.bin);;All files (*)"); + break; + case Types::NvramEntryFlashMap: + path = QFileDialog::getSaveFileName(this, tr("Save FlashMap entry to file"), name + ".fme", "FlashMap entry files (*.fme *.bin);;All files (*)"); break; case Types::NvramStoreVss: + path = QFileDialog::getSaveFileName(this, tr("Save VSS store to file"), name + ".vss", "VSS store files (*.vss *.bin);;All files (*)"); + break; case Types::NvramStoreFdc: - path = QFileDialog::getSaveFileName(this, tr("Save variable store to file"), name + ".vss", "Variable store files (*.vss *.bin);;All files (*)"); + path = QFileDialog::getSaveFileName(this, tr("Save FDC store to file"), name + ".fdc", "FDC store files (*.fdc *.bin);;All files (*)"); break; case Types::NvramStoreFsys: path = QFileDialog::getSaveFileName(this, tr("Save Fsys store to file"), name + ".fsys", "Fsys store files (*.fsys *.bin);;All files (*)"); @@ -550,8 +565,11 @@ void UEFITool::extract(const UINT8 mode) case Types::NvramStoreEvsa: path = QFileDialog::getSaveFileName(this, tr("Save EVSA store to file"), name + ".evsa", "EVSA store files (*.evsa *.bin);;All files (*)"); break; - case Types::NvramFtwBlock: - path = QFileDialog::getSaveFileName(this, tr("Save FTW block to file"), name + ".ftw", "FTW block files (*.ftw *.bin);;All files (*)"); + case Types::NvramStoreFtw: + path = QFileDialog::getSaveFileName(this, tr("Save FTW store to file"), name + ".ftw", "FTW store files (*.ftw *.bin);;All files (*)"); + break; + case Types::NvramStoreFlashMap: + path = QFileDialog::getSaveFileName(this, tr("Save FlashMap store to file"), name + ".fmap", "FlashMap store files (*.fmap *.bin);;All files (*)"); break; default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)"); @@ -587,11 +605,12 @@ void UEFITool::extract(const UINT8 mode) break; case Types::NvramVariableNvar: case Types::NvramVariableVss: + case Types::NvramEntryEvsa: path = QFileDialog::getSaveFileName(this, tr("Save variable body to file"), name + ".bin", "Binary files (*.bin);;All files (*)"); break; case Types::NvramStoreVss: case Types::NvramStoreFdc: - path = QFileDialog::getSaveFileName(this, tr("Save variable store body to file"), name + ".vsb", "Variable store body files (*.vsb *.bin);;All files (*)"); + path = QFileDialog::getSaveFileName(this, tr("Save VSS variable store body to file"), name + ".vsb", "VSS variable store body files (*.vsb *.bin);;All files (*)"); break; case Types::NvramStoreFsys: path = QFileDialog::getSaveFileName(this, tr("Save Fsys store body to file"), name + ".fsb", "Fsys store body files (*.fsb *.bin);;All files (*)"); @@ -599,8 +618,11 @@ void UEFITool::extract(const UINT8 mode) case Types::NvramStoreEvsa: path = QFileDialog::getSaveFileName(this, tr("Save EVSA store body to file"), name + ".esb", "EVSA store body files (*.esb *.bin);;All files (*)"); 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 (*)"); + case Types::NvramStoreFtw: + path = QFileDialog::getSaveFileName(this, tr("Save FTW store body to file"), name + ".ftb", "FTW store body files (*.ftb *.bin);;All files (*)"); + break; + case Types::NvramStoreFlashMap: + path = QFileDialog::getSaveFileName(this, tr("Save FlashMap store body to file"), name + ".fmb", "FlashMap store body files (*.fmb *.bin);;All files (*)"); break; default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", "Binary files (*.bin);;All files (*)"); @@ -962,14 +984,17 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event) break; case Types::NvramVariableNvar: case Types::NvramVariableVss: - case Types::NvramVariableFsys: + case Types::NvramEntryFsys: + case Types::NvramEntryEvsa: + case Types::NvramEntryFlashMap: ui->menuVariableActions->exec(event->globalPos()); break; case Types::NvramStoreVss: case Types::NvramStoreFdc: case Types::NvramStoreFsys: case Types::NvramStoreEvsa: - case Types::NvramFtwBlock: + case Types::NvramStoreFtw: + case Types::NvramStoreFlashMap: ui->menuStoreActions->exec(event->globalPos()); break; } diff --git a/common/ffsops.cpp b/common/ffsops.cpp index aabe202..7454374 100644 --- a/common/ffsops.cpp +++ b/common/ffsops.cpp @@ -59,27 +59,18 @@ STATUS FfsOperations::extract(const QModelIndex & index, QString & name, QByteAr case Types::NvramVariableNvar: case Types::NvramVariableVss: case Types::File: { - name = itemText.isEmpty() ? itemName : itemText.replace(' ', '_'); + name = itemText.isEmpty() ? itemName : itemText.replace(' ', '_').replace('-', '_'); } break; case Types::Section: { // Get parent file name QModelIndex fileIndex = model->findParentOfType(index, Types::File); QString fileText = model->text(fileIndex); - name = fileText.isEmpty() ? model->name(fileIndex) : fileText.replace(' ', '_'); + name = fileText.isEmpty() ? model->name(fileIndex) : fileText.replace(' ', '_').replace('-', '_'); // Append section subtype name name += QChar('_') + itemName.replace(' ', '_'); } break; - case Types::Capsule: - case Types::Image: - case Types::Region: - case Types::Padding: - case Types::NvramStoreVss: - case Types::NvramStoreFdc: - case Types::NvramStoreFsys: - case Types::NvramStoreEvsa: - case Types::NvramFtwBlock: default: - name = itemName.replace(' ', '_').replace('/', '_'); + name = itemName.replace(' ', '_').replace('/', '_').replace('-', '_'); } // Get extracted data diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp index 882067f..8af277a 100644 --- a/common/ffsparser.cpp +++ b/common/ffsparser.cpp @@ -3366,7 +3366,10 @@ STATUS FfsParser::parseStoreArea(const QByteArray & data, const QModelIndex & in case Types::NvramStoreEvsa: parseEvsaStoreBody(current); break; - case Types::NvramFtwBlock: + case Types::NvramStoreFlashMap: + parseFlashMapBody(current); + break; + case Types::NvramStoreFtw: case Types::Padding: // No parsing required break; @@ -3410,7 +3413,7 @@ STATUS FfsParser::findNextStore(const QModelIndex & index, const QByteArray & da // All checks passed, store found break; } - else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { //Fsys signature found + else if (*currentPos == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *currentPos == NVRAM_APPLE_GAID_STORE_SIGNATURE) { //Fsys or Gaid signature found 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); @@ -3435,8 +3438,9 @@ STATUS FfsParser::findNextStore(const QModelIndex & index, const QByteArray & da offset -= 4; 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 + else if (*currentPos == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *currentPos == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { //Possible FTW block signature found + QByteArray guid = QByteArray(data.constData() + offset, sizeof(EFI_GUID)); + if (guid != NVRAM_MAIN_STORE_VOLUME_GUID && guid != EDKII_WORKING_BLOCK_SIGNATURE_GUID) // Check the whole signature continue; // Detect header variant based on WriteQueueSize @@ -3460,6 +3464,14 @@ STATUS FfsParser::findNextStore(const QModelIndex & index, const QByteArray & da // All checks passed, store found break; } + else if (*currentPos == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) {// Phoenix SCT flash map + QByteArray signature = QByteArray(data.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; + } } // No more stores found if (offset >= dataSize - sizeof(UINT32)) @@ -3481,7 +3493,7 @@ STATUS FfsParser::getStoreSize(const QByteArray & data, const UINT32 storeOffset const FDC_VOLUME_HEADER* fdcHeader = (const FDC_VOLUME_HEADER*)signature; storeSize = fdcHeader->Size; } - else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { + else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE) { const APPLE_FSYS_STORE_HEADER* fsysHeader = (const APPLE_FSYS_STORE_HEADER*)signature; storeSize = fsysHeader->Size; } @@ -3489,7 +3501,7 @@ STATUS FfsParser::getStoreSize(const QByteArray & data, const UINT32 storeOffset const EVSA_STORE_ENTRY* evsaHeader = (const EVSA_STORE_ENTRY*)signature; storeSize = evsaHeader->StoreSize; } - else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1) { + else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_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; @@ -3499,6 +3511,10 @@ STATUS FfsParser::getStoreSize(const QByteArray & data, const UINT32 storeOffset storeSize = sizeof(EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64) + ftw64Header->WriteQueueSize; } } + else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) { // Phoenix SCT flash map + const PHOENIX_FLASH_MAP_HEADER* flashMapHeader = (const PHOENIX_FLASH_MAP_HEADER*)signature; + storeSize = sizeof(PHOENIX_FLASH_MAP_HEADER) + sizeof(PHOENIX_FLASH_MAP_ENTRY) * flashMapHeader->NumEntries; + } return ERR_SUCCESS; } @@ -3516,7 +3532,7 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent // VSS variable stores if (*signature == NVRAM_VSS_STORE_SIGNATURE || *signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) { - // The volume must begin with a store to be valid, but after the first one, there can be many variants + // Check dataSize if (dataSize < sizeof(VSS_VARIABLE_STORE_HEADER)) { msg(QObject::tr("parseStoreHeader: volume body is too small even for VSS store header"), parent); return ERR_SUCCESS; @@ -3528,8 +3544,8 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent // Check store size if (dataSize < vssStoreHeader->Size) { msg(QObject::tr("parseStoreHeader: VSS store size %1h (%2) is greater than volume body size %3h (%4)") - .hexarg2(vssStoreHeader->Size, 8).arg(vssStoreHeader->Size) - .hexarg2(dataSize, 8).arg(dataSize), parent); + .hexarg(vssStoreHeader->Size).arg(vssStoreHeader->Size) + .hexarg(dataSize).arg(dataSize), parent); return ERR_SUCCESS; } @@ -3541,18 +3557,15 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent QByteArray body = store.mid(sizeof(VSS_VARIABLE_STORE_HEADER), vssStoreHeader->Size - sizeof(VSS_VARIABLE_STORE_HEADER)); // Add info - QString name = QObject::tr("VSS store"); - QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nFormat: %8h\nState: %9h") + QString name = (*signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) ? QObject::tr("SVS store") : QObject::tr("VSS store"); + QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nFormat: %8h\nState: %9h\nUnknown: %10h") .hexarg2(vssStoreHeader->Signature, 8) .hexarg(vssStoreHeader->Size).arg(vssStoreHeader->Size) .hexarg(header.size()).arg(header.size()) .hexarg(body.size()).arg(body.size()) .hexarg2(vssStoreHeader->Format, 2) - .hexarg2(vssStoreHeader->State, 2); - - // Add unknown field for $SVS stores - if (*signature == NVRAM_APPLE_SVS_STORE_SIGNATURE) - info += QObject::tr("\nUnknown: %1h").hexarg2(vssStoreHeader->Unknown, 4); + .hexarg2(vssStoreHeader->State, 2) + .hexarg2(vssStoreHeader->Unknown, 4); // Add correct offset pdata.offset = parentOffset; @@ -3561,7 +3574,7 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent index = model->addItem(Types::NvramStoreVss, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent); } else if (*signature == NVRAM_FDC_VOLUME_SIGNATURE) { - // The volume must begin with a store to be valid, but after the first one, there can be many variants + // Check dataSize if (dataSize < sizeof(FDC_VOLUME_HEADER)) { msg(QObject::tr("parseStoreHeader: volume body is too small even for FDC store header"), parent); return ERR_SUCCESS; @@ -3573,8 +3586,8 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent // Check store size if (dataSize < fdcStoreHeader->Size) { msg(QObject::tr("parseStoreHeader: FDC store size %1h (%2) is greater than volume body size %3h (%4)") - .hexarg2(fdcStoreHeader->Size, 8).arg(fdcStoreHeader->Size) - .hexarg2(dataSize, 8).arg(dataSize), parent); + .hexarg(fdcStoreHeader->Size).arg(fdcStoreHeader->Size) + .hexarg(dataSize).arg(dataSize), parent); return ERR_SUCCESS; } @@ -3628,8 +3641,8 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent // Add tree item index = model->addItem(Types::NvramStoreFdc, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent); } - else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE) { - // The volume must begin with a store to be valid, but after the first one, there can be many variants + else if (*signature == NVRAM_APPLE_FSYS_STORE_SIGNATURE || *signature == NVRAM_APPLE_GAID_STORE_SIGNATURE) { + // Check dataSize if (dataSize < sizeof(APPLE_FSYS_STORE_HEADER)) { msg(QObject::tr("parseStoreHeader: volume body is too small even for Fsys store header"), parent); return ERR_SUCCESS; @@ -3641,8 +3654,8 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent // Check store size if (dataSize < fsysStoreHeader->Size) { msg(QObject::tr("parseStoreHeader: Fsys store size %1h (%2) is greater than volume body size %3h (%4)") - .hexarg2(fsysStoreHeader->Size, 4).arg(fsysStoreHeader->Size) - .hexarg2(dataSize, 8).arg(dataSize), parent); + .hexarg(fsysStoreHeader->Size).arg(fsysStoreHeader->Size) + .hexarg(dataSize).arg(dataSize), parent); return ERR_SUCCESS; } @@ -3658,7 +3671,7 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent UINT32 calculatedCrc = calculatedCrc = crc32(0, (const UINT8*)store.constData(), (const UINT32)store.size() - sizeof(UINT32)); // Add info - QString name = QObject::tr("Fsys store"); + QString name = (*signature == NVRAM_APPLE_GAID_STORE_SIGNATURE) ? QObject::tr("Gaid store") : QObject::tr("Fsys store"); QString info = QObject::tr("Signature: %1h\nFull size: %2h (%3)\nHeader size: %4h (%5)\nBody size: %6h (%7)\nUnknown: %9 %10 %11 %12 %13\nCRC32: %14") .hexarg2(fsysStoreHeader->Signature, 8) .hexarg(fsysStoreHeader->Size).arg(fsysStoreHeader->Size) @@ -3678,7 +3691,7 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent index = model->addItem(Types::NvramStoreFsys, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent); } else if (*(signature + 1) == NVRAM_EVSA_STORE_SIGNATURE) { - // The volume must begin with a store to be valid, but after the first one, there can be many variants + // Check dataSize if (dataSize < sizeof(EVSA_STORE_ENTRY)) { msg(QObject::tr("parseStoreHeader: volume body is too small even for EVSA store header"), parent); return ERR_SUCCESS; @@ -3690,8 +3703,8 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent // Check store size if (dataSize < evsaStoreHeader->StoreSize) { msg(QObject::tr("parseStoreHeader: EVSA store size %1h (%2) is greater than volume body size %3h (%4)") - .hexarg2(evsaStoreHeader->StoreSize, 4).arg(evsaStoreHeader->StoreSize) - .hexarg2(dataSize, 8).arg(dataSize), parent); + .hexarg(evsaStoreHeader->StoreSize).arg(evsaStoreHeader->StoreSize) + .hexarg(dataSize).arg(dataSize), parent); return ERR_SUCCESS; } @@ -3724,8 +3737,8 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent // Add tree item 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 + else if (*signature == NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 || *signature == EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1) { + // Check dataSize 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; @@ -3748,8 +3761,8 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent } 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); + .hexarg(ftwBlockSize).arg(ftwBlockSize) + .hexarg(dataSize).arg(dataSize), parent); return ERR_SUCCESS; } @@ -3784,7 +3797,46 @@ STATUS FfsParser::parseStoreHeader(const QByteArray & store, const UINT32 parent pdata.offset = parentOffset; // Add tree item - index = model->addItem(Types::NvramFtwBlock, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent); + index = model->addItem(Types::NvramStoreFtw, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent); + } + else if (*signature == NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1) { // Phoenix SCT flash map + if (dataSize < sizeof(PHOENIX_FLASH_MAP_HEADER)) { + msg(QObject::tr("parseStoreHeader: volume body is too small even for FlashMap block header"), parent); + return ERR_SUCCESS; + } + + // Get FlashMap block header + const PHOENIX_FLASH_MAP_HEADER* flashMapHeader = (const PHOENIX_FLASH_MAP_HEADER*)signature; + + // Check store size + UINT32 flashMapSize = sizeof(PHOENIX_FLASH_MAP_HEADER) + flashMapHeader->NumEntries * sizeof(PHOENIX_FLASH_MAP_ENTRY); + if (dataSize < flashMapSize) { + msg(QObject::tr("parseStoreHeader: FlashMap block size %1h (%2) is greater than volume body size %3h (%4)") + .hexarg(flashMapSize).arg(flashMapSize) + .hexarg(dataSize).arg(dataSize), parent); + return ERR_SUCCESS; + } + + // Get parsing data + PARSING_DATA pdata = parsingDataFromQModelIndex(parent); + + // Construct header and body + QByteArray header = store.left(sizeof(PHOENIX_FLASH_MAP_HEADER)); + QByteArray body = store.mid(sizeof(PHOENIX_FLASH_MAP_HEADER), flashMapSize - sizeof(PHOENIX_FLASH_MAP_HEADER)); + + // Add info + QString name = QObject::tr("Phoenix SCT FlashMap"); + QString info = QObject::tr("Signature: _FLASH_MAP\nFull size: %1h (%2)\nHeader size: %3h (%4)\nBody size: %5h (%6)\nNumber of entries: %7") + .hexarg(flashMapSize).arg(flashMapSize) + .hexarg(header.size()).arg(header.size()) + .hexarg(body.size()).arg(body.size()) + .arg(flashMapHeader->NumEntries); + + // Add correct offset + pdata.offset = parentOffset; + + // Add tree item + index = model->addItem(Types::NvramStoreFlashMap, 0, name, QString(), info, header, body, TRUE, parsingDataToQByteArray(pdata), parent); } return ERR_SUCCESS; @@ -4036,7 +4088,7 @@ STATUS FfsParser::parseFsysStoreBody(const QModelIndex & index) pdata.offset = parentOffset + offset; // Add EOF tree item - model->addItem(Types::NvramVariableFsys, 0, name, QString(), info, header, QByteArray(), FALSE, parsingDataToQByteArray(pdata), index); + model->addItem(Types::NvramEntryFsys, 0, name, QString(), info, header, QByteArray(), FALSE, parsingDataToQByteArray(pdata), index); // Add free space offset += header.size(); @@ -4092,7 +4144,7 @@ STATUS FfsParser::parseFsysStoreBody(const QModelIndex & index) pdata.offset = parentOffset + offset; // Add tree item - model->addItem(Types::NvramVariableFsys, 0, name, QString(), info, header, body, FALSE, parsingDataToQByteArray(pdata), index); + model->addItem(Types::NvramEntryFsys, 0, name, QString(), info, header, body, FALSE, parsingDataToQByteArray(pdata), index); // Move to next variable offset += variableSize; @@ -4162,7 +4214,9 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index) entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_GUID2) { const EVSA_GUID_ENTRY* guidHeader = (const EVSA_GUID_ENTRY*)entryHeader; header = data.mid(offset, sizeof(EVSA_GUID_ENTRY)); - name = guidToQString(guidHeader->Guid); + body = data.mid(offset + sizeof(EVSA_GUID_ENTRY), guidHeader->Header.Size - sizeof(EVSA_GUID_ENTRY)); + EFI_GUID guid = *(EFI_GUID*)body.constData(); + name = guidToQString(guid); info = QObject::tr("Full size: %1h (%2)\nHeader size %3h (%4)\nBody size: %5h (%6)\nType: %7h\nChecksum: %8\nGuidId: %9h") .hexarg(variableSize).arg(variableSize) .hexarg(header.size()).arg(header.size()) @@ -4173,7 +4227,7 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index) QObject::tr("%1h, invalid, should be %2h").hexarg2(guidHeader->Header.Checksum, 2).hexarg2(calculated, 2)) .hexarg2(guidHeader->GuidId, 4); subtype = Subtypes::GuidEvsaEntry; - guidMap.insert(std::pair(guidHeader->GuidId, guidHeader->Guid)); + guidMap.insert(std::pair(guidHeader->GuidId, guid)); } // Name entry else if (entryHeader->Type == NVRAM_EVSA_ENTRY_TYPE_NAME1 || @@ -4282,3 +4336,69 @@ STATUS FfsParser::parseEvsaStoreBody(const QModelIndex & index) } +STATUS FfsParser::parseFlashMapBody(const QModelIndex & index) +{ + // Sanity check + if (!index.isValid()) + return ERR_INVALID_PARAMETER; + + // Get parsing data for the current item + PARSING_DATA pdata = parsingDataFromQModelIndex(index); + UINT32 parentOffset = pdata.offset + model->header(index).size(); + const QByteArray 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 + 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("parseFlashMapBody: next entry appears too big, added as padding"), index); + + break; + } + + QString name = guidToQString(entryHeader->Guid); + + // Construct header + QByteArray header = data.mid(offset, sizeof(PHOENIX_FLASH_MAP_ENTRY)); + + // Add info + QString info = QObject::tr("Entry GUID: %1\nFull size: 24h (36)\nHeader size %2h (%3)\nBody size: 0h (0)\nType %4h\nMemory address: %5h\nSize: %6h\nOffset: %7h") + .arg(name) + .hexarg(header.size()).arg(header.size()) + .hexarg2(entryHeader->Type, 8) + .hexarg2(entryHeader->PhysicalAddress, 8) + .hexarg2(entryHeader->Size, 8) + .hexarg2(entryHeader->Offset, 8); + + // Add correct offset to parsing data + pdata.offset = parentOffset + offset; + + // Add tree item + model->addItem(Types::NvramEntryFlashMap, 0, name, QString(), info, header, QByteArray(), TRUE, parsingDataToQByteArray(pdata), index); + + // Move to next variable + offset += sizeof(PHOENIX_FLASH_MAP_ENTRY); + unparsedSize = dataSize - offset; + } + + return ERR_SUCCESS; +} diff --git a/common/ffsparser.h b/common/ffsparser.h index e0c4c0d..f070029 100644 --- a/common/ffsparser.h +++ b/common/ffsparser.h @@ -116,6 +116,7 @@ private: STATUS parseVssStoreBody(const QModelIndex & index); STATUS parseFsysStoreBody(const QModelIndex & index); STATUS parseEvsaStoreBody(const QModelIndex & index); + STATUS parseFlashMapBody(const QModelIndex & index); // Message helper void msg(const QString & message, const QModelIndex &index = QModelIndex()); diff --git a/common/nvram.h b/common/nvram.h index 3386270..7fc72df 100644 --- a/common/nvram.h +++ b/common/nvram.h @@ -73,7 +73,6 @@ typedef struct NVAR_VARIABLE_HEADER_ { // FFF12B8D-7696-4C8B-A985-2747075B4F50 const QByteArray NVRAM_MAIN_STORE_VOLUME_GUID ("\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 const QByteArray NVRAM_ADDITIONAL_STORE_VOLUME_GUID @@ -82,6 +81,7 @@ const QByteArray NVRAM_ADDITIONAL_STORE_VOLUME_GUID #define NVRAM_VSS_STORE_SIGNATURE 0x53535624 // $VSS #define NVRAM_APPLE_SVS_STORE_SIGNATURE 0x53565324 // $SVS #define NVRAM_APPLE_FSYS_STORE_SIGNATURE 0x73797346 // Fsys +#define NVRAM_APPLE_GAID_STORE_SIGNATURE 0x64696147 // Gaid #define NVRAM_VSS_VARIABLE_START_ID 0x55AA // Variable store header flags @@ -158,14 +158,14 @@ typedef struct VSS_AUTH_VARIABLE_HEADER_ { #define NVRAM_VSS_VARIABLE_APPEND_WRITE 0x00000040 #define NVRAM_VSS_VARIABLE_APPLE_DATA_CHECKSUM 0x80000000 -// FDC region can be found in some VSS volumes +// FDC region can be found in Insyde VSS volumes // It has another VSS volume inside // _FDC header structure #define NVRAM_FDC_VOLUME_SIGNATURE 0x4344465F typedef struct FDC_VOLUME_HEADER_ { UINT32 Signature; //_FDC - UINT32 Size; + UINT32 Size; // Size of the whole region //EFI_FIRMWARE_VOLUME_HEADER VolumeHeader; //EFI_FV_BLOCK_MAP_ENTRY FvBlockMap[2]; //VSS_VARIABLE_STORE_HEADER VssHeader; @@ -175,20 +175,28 @@ typedef struct FDC_VOLUME_HEADER_ { // EFI Fault tolerant working block header #define EFI_FAULT_TOLERANT_WORKING_BLOCK_VALID 0x1 #define EFI_FAULT_TOLERANT_WORKING_BLOCK_INVALID 0x2 -typedef struct { + +// 9E58292B-7C68-497D-0ACE6500FD9F1B95 +const QByteArray EDKII_WORKING_BLOCK_SIGNATURE_GUID +("\x2B\x29\x58\x9E\x68\x7C\x7D\x49\x0A\xCE\x65\x00\xFD\x9F\x1B\x95", 16); + +#define NVRAM_MAIN_STORE_VOLUME_GUID_DATA1 0xFFF12B8D +#define EDKII_WORKING_BLOCK_SIGNATURE_GUID_DATA1 0x9E58292B + +typedef struct EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32_ { 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]; + UINT8 Reserved[3]; UINT32 WriteQueueSize; // Size of the FTW block without the header //UINT8 WriteQueue[WriteQueueSize]; } EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER32; -typedef struct { +typedef struct EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64_ { 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]; + UINT8 Reserved[3]; UINT64 WriteQueueSize; // Size of the FTW block without the header //UINT8 WriteQueue[WriteQueueSize]; } EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER64; @@ -203,7 +211,7 @@ typedef struct APPLE_FSYS_STORE_HEADER_ { UINT16 Size; // Size of variable store } APPLE_FSYS_STORE_HEADER; -// Apple Fsys variable format +// Apple Fsys entry format // UINT8 NameLength; // CHAR8 Name[]; // UINT16 DataLength; @@ -244,7 +252,7 @@ typedef struct EVSA_STORE_ENTRY_ { typedef struct EVSA_GUID_ENTRY_ { EVSA_ENTRY_HEADER Header; UINT16 GuidId; - EFI_GUID Guid; + //EFI_GUID Guid; } EVSA_GUID_ENTRY; typedef struct EVSA_NAME_ENTRY_ { @@ -261,6 +269,36 @@ typedef struct EVSA_DATA_ENTRY_ { //UINT8 Data[]; } EVSA_DATA_ENTRY; + +// +// Phoenix SCT Flash Map +// + +#define NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_PART1 0x414C465F +#define NVRAM_PHOENIX_FLASH_MAP_SIGNATURE_LENGTH 10 + +// _FLASH_MAP +const QByteArray NVRAM_PHOENIX_FLASH_MAP_SIGNATURE +("\x5F\x46\x4C\x41\x53\x48\x5F\x4D\x41\x50", 10); + +typedef struct PHOENIX_FLASH_MAP_HEADER_ { + UINT8 Signature[10]; // _FLASH_MAP signature + UINT16 NumEntries; // Number of entries in the map + UINT32 : 32; // Reserved field +} PHOENIX_FLASH_MAP_HEADER; + +typedef struct PHOENIX_FLASH_MAP_ENTRY_ { + EFI_GUID Guid; + UINT32 Type; + UINT64 PhysicalAddress; + UINT32 Size; + UINT32 Offset; +} PHOENIX_FLASH_MAP_ENTRY; + + + + + // Restore previous packing rules #pragma pack(pop) diff --git a/common/types.cpp b/common/types.cpp index e18e5ef..a05018d 100644 --- a/common/types.cpp +++ b/common/types.cpp @@ -73,16 +73,20 @@ QString itemTypeToQString(const UINT8 type) return QObject::tr("Fsys store"); case Types::NvramStoreEvsa: return QObject::tr("EVSA store"); - case Types::NvramFtwBlock: - return QObject::tr("FTW block"); + case Types::NvramStoreFtw: + return QObject::tr("FTW store"); + case Types::NvramStoreFlashMap: + return QObject::tr("FlashMap store"); case Types::NvramVariableNvar: return QObject::tr("NVAR variable"); case Types::NvramVariableVss: return QObject::tr("VSS variable"); - case Types::NvramVariableFsys: - return QObject::tr("Fsys variable"); + case Types::NvramEntryFsys: + return QObject::tr("Fsys entry"); case Types::NvramEntryEvsa: return QObject::tr("EVSA entry"); + case Types::NvramEntryFlashMap: + return QObject::tr("FlashMap entry"); default: return QObject::tr("Unknown"); } @@ -142,8 +146,10 @@ QString itemSubtypeToQString(const UINT8 type, const UINT8 subtype) case Types::NvramStoreFdc: case Types::NvramStoreFsys: case Types::NvramStoreEvsa: - case Types::NvramFtwBlock: - case Types::NvramVariableFsys: + case Types::NvramStoreFtw: + case Types::NvramStoreFlashMap: + case Types::NvramEntryFsys: + case Types::NvramEntryFlashMap: return QString(); case Types::NvramVariableNvar: if (subtype == Subtypes::InvalidNvarVariable) diff --git a/common/types.h b/common/types.h index cd3017c..20cf0d5 100644 --- a/common/types.h +++ b/common/types.h @@ -47,11 +47,13 @@ namespace Types { NvramStoreFdc, NvramStoreFsys, NvramStoreEvsa, - NvramFtwBlock, + NvramStoreFlashMap, + NvramStoreFtw, NvramVariableNvar, NvramVariableVss, - NvramVariableFsys, - NvramEntryEvsa + NvramEntryFsys, + NvramEntryEvsa, + NvramEntryFlashMap, }; }