diff --git a/UEFITool/uefitool.cpp b/UEFITool/uefitool.cpp
index 354014f..c3d0ff9 100644
--- a/UEFITool/uefitool.cpp
+++ b/UEFITool/uefitool.cpp
@@ -192,11 +192,24 @@ 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->menuEntryActions->setEnabled(type == Types::NvarEntry
+ ui->menuEntryActions->setEnabled(type == Types::Microcode
+ || type == Types::SlicData
+ || type == Types::NvarEntry
|| type == Types::VssEntry
|| type == Types::FsysEntry
|| type == Types::EvsaEntry
- || type == Types::FlashMapEntry);
+ || type == Types::FlashMapEntry
+ || type == Types::IfwiHeader
+ || type == Types::IfwiPartition
+ || type == Types::FptPartition
+ || type == Types::FptEntry
+ || type == Types::BpdtPartition
+ || type == Types::BpdtEntry
+ || type == Types::CpdPartition
+ || type == Types::CpdEntry
+ || type == Types::CpdExtension
+ || type == Types::CpdSpiEntry
+ );
ui->menuStoreActions->setEnabled(type == Types::VssStore
|| type == Types::Vss2Store
|| type == Types::FdcStore
@@ -204,9 +217,11 @@ void UEFITool::populateUi(const QModelIndex ¤t)
|| type == Types::EvsaStore
|| type == Types::FtwStore
|| type == Types::FlashMapStore
- || type == Types::CmdbStore
- || type == Types::Microcode
- || type == Types::SlicData);
+ || type == Types::CmdbStore
+ || type == Types::FptStore
+ || type == Types::BpdtStore
+ || type == Types::CpdStore
+ );
// Enable actions
ui->actionHexView->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
@@ -481,7 +496,7 @@ void UEFITool::extract(const UINT8 mode)
if (subtype == Subtypes::PubkeySlicData) path = QFileDialog::getSaveFileName(this, tr("Save SLIC pubkey to file"), name + ".spk", tr("SLIC pubkey files (*.spk *.bin);;All files (*)"));
else path = QFileDialog::getSaveFileName(this, tr("Save SLIC marker to file"), name + ".smk", tr("SLIC marker files (*.smk *.bin);;All files (*)"));
break;
- default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)"));
+ default: path = QFileDialog::getSaveFileName(this, tr("Save object to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)"));
}
}
else if (mode == EXTRACT_MODE_BODY || mode == EXTRACT_MODE_BODY_UNCOMPRESSED) {
@@ -553,7 +568,7 @@ void UEFITool::remove()
void UEFITool::about()
{
QMessageBox::about(this, tr("About UEFITool"), tr(
- "Copyright (c) 2018, LongSoft.
"
+ "Copyright (c) 2019, Nikolaj Schlej.
"
"Program icon made by Alexander Zhidkov.
"
"The program uses QHexEdit2 library made by Simsys.
"
"Qt-less engine is using Bstrlib made by Paul Hsieh.
"
@@ -858,8 +873,11 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
case Types::EvsaStore:
case Types::FtwStore:
case Types::FlashMapStore:
- case Types::CmdbStore: ui->menuStoreActions->exec(event->globalPos()); break;
- case Types::FreeSpace: break;
+ case Types::CmdbStore:
+ case Types::FptStore:
+ case Types::CpdStore:
+ case Types::BpdtStore: ui->menuStoreActions->exec(event->globalPos()); break;
+ case Types::FreeSpace: break; // No menu needed for FreeSpace item
default: ui->menuEntryActions->exec(event->globalPos()); break;
}
}
diff --git a/UEFITool/uefitool.pro b/UEFITool/uefitool.pro
index 4225e51..64cfc18 100644
--- a/UEFITool/uefitool.pro
+++ b/UEFITool/uefitool.pro
@@ -5,6 +5,7 @@ TARGET = UEFITool
TEMPLATE = app
DEFINES += "U_ENABLE_FIT_PARSING_SUPPORT"
DEFINES += "U_ENABLE_NVRAM_PARSING_SUPPORT"
+DEFINES += "U_ENABLE_ME_PARSING_SUPPORT"
DEFINES += "U_ENABLE_GUID_DATABASE_SUPPORT"
HEADERS += uefitool.h \
@@ -70,6 +71,7 @@ SOURCES += uefitool_main.cpp \
../common/guiddatabase.cpp \
../common/nvram.cpp \
../common/nvramparser.cpp \
+ ../common/meparser.cpp \
../common/ffsops.cpp \
../common/types.cpp \
../common/descriptor.cpp \
diff --git a/common/Tiano/EfiTianoDecompress.c b/common/Tiano/EfiTianoDecompress.c
index 41f38ec..fbcd8ca 100644
--- a/common/Tiano/EfiTianoDecompress.c
+++ b/common/Tiano/EfiTianoDecompress.c
@@ -711,10 +711,6 @@ Decode (
UINT32 DataIdx;
UINT16 CharC;
- BytesRemain = (UINT16)(-1);
-
- DataIdx = 0;
-
for (;;) {
//
// Get one code from mBitBuf
diff --git a/common/basetypes.h b/common/basetypes.h
index de4ae3b..a16030f 100644
--- a/common/basetypes.h
+++ b/common/basetypes.h
@@ -68,6 +68,19 @@ typedef size_t USTATUS;
#define U_INVALID_BG_BOOT_POLICY 46
#define U_INVALID_TXT_CONF 47
#define U_ELEMENTS_NOT_FOUND 48
+#define U_PEI_CORE_ENTRY_POINT_NOT_FOUND 49
+#define U_INVALID_STORE_SIZE 50
+#define U_UNKNOWN_COMPRESSION_ALGORITHM 51
+#define U_NOTHING_TO_PATCH 52
+#define U_UNKNOWN_PATCH_TYPE 53
+#define U_PATCH_OFFSET_OUT_OF_BOUNDS 54
+#define U_INVALID_SYMBOL 55
+
+#define U_INVALID_MANIFEST 251
+#define U_UNKNOWN_MANIFEST_HEADER_VERSION 252
+#define U_INVALID_ME_PARTITION_TABLE 253
+#define U_INVALID_ME_PARTITION 254
+
#define U_NOT_IMPLEMENTED 0xFF
// EDK2 porting definitions
diff --git a/common/ffs.cpp b/common/ffs.cpp
index ed414a8..de9a274 100644
--- a/common/ffs.cpp
+++ b/common/ffs.cpp
@@ -39,16 +39,16 @@ const UINT8 ffsAlignment2Table[] =
VOID uint32ToUint24(UINT32 size, UINT8* ffsSize)
{
- ffsSize[2] = (UINT8)((size) >> 16);
- ffsSize[1] = (UINT8)((size) >> 8);
+ ffsSize[2] = (UINT8)((size) >> 16U);
+ ffsSize[1] = (UINT8)((size) >> 8U);
ffsSize[0] = (UINT8)((size));
}
UINT32 uint24ToUint32(const UINT8* ffsSize)
{
return (UINT32) ffsSize[0]
- + ((UINT32) ffsSize[1] << 8U)
- + ((UINT32) ffsSize[2] << 16U);
+ + ((UINT32) ffsSize[1] << 8U)
+ + ((UINT32) ffsSize[2] << 16U);
}
UString guidToUString(const EFI_GUID & guid, bool convertToString)
@@ -84,17 +84,17 @@ bool ustringToGuid(const UString & str, EFI_GUID & guid)
if (err == 0)
return false;
- guid.Data1 = p0;
- guid.Data2 = p1;
- guid.Data3 = p2;
- guid.Data4[0] = p3;
- guid.Data4[1] = p4;
- guid.Data4[2] = p5;
- guid.Data4[3] = p6;
- guid.Data4[4] = p7;
- guid.Data4[5] = p8;
- guid.Data4[6] = p9;
- guid.Data4[7] = p10;
+ guid.Data1 = (UINT32)p0;
+ guid.Data2 = (UINT16)p1;
+ guid.Data3 = (UINT16)p2;
+ guid.Data4[0] = (UINT8)p3;
+ guid.Data4[1] = (UINT8)p4;
+ guid.Data4[2] = (UINT8)p5;
+ guid.Data4[3] = (UINT8)p6;
+ guid.Data4[4] = (UINT8)p7;
+ guid.Data4[5] = (UINT8)p8;
+ guid.Data4[6] = (UINT8)p9;
+ guid.Data4[7] = (UINT8)p10;
return true;
}
diff --git a/common/ffs.h b/common/ffs.h
index 4103961..4a7ccae 100644
--- a/common/ffs.h
+++ b/common/ffs.h
@@ -571,6 +571,21 @@ typedef struct POSTCODE_SECTION_ {
///
#define EFI_DEP_SOR 0x09
+//*****************************************************************************
+// X86 Reset Vector Data
+//*****************************************************************************
+typedef struct X86_RESET_VECTOR_DATA_ {
+ UINT8 ApEntryVector[8]; // Base: 0xffffffd0
+ UINT8 Reserved0[8];
+ UINT32 PeiCoreEntryPoint; // Base: 0xffffffe0
+ UINT8 Reserved1[12];
+ UINT8 ResetVector[8]; // Base: 0xfffffff0
+ UINT32 ApStartupSegment; // Base: 0xfffffff8
+ UINT32 BootFvBaseAddress; // Base: 0xfffffffc
+} X86_RESET_VECTOR_DATA;
+
+#define X86_RESET_VECTOR_DATA_UNPOPULATED 0x12345678
+
// Restore previous packing rules
#pragma pack(pop)
diff --git a/common/ffsparser.cpp b/common/ffsparser.cpp
index 0336026..7432f0e 100644
--- a/common/ffsparser.cpp
+++ b/common/ffsparser.cpp
@@ -120,7 +120,7 @@ USTATUS FfsParser::parse(const UByteArray & buffer)
USTATUS FfsParser::performFirstPass(const UByteArray & buffer, UModelIndex & index)
{
- // Sanity check
+ // Sanity check
if (buffer.isEmpty()) {
return EFI_INVALID_PARAMETER;
}
@@ -756,7 +756,7 @@ USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffs
// Parse PDR region as BIOS space
USTATUS result = parseRawArea(index);
- if (result && result != U_VOLUMES_NOT_FOUND && result != U_INVALID_VOLUME)
+ if (result && result != U_VOLUMES_NOT_FOUND && result != U_INVALID_VOLUME && result != U_STORES_NOT_FOUND)
return result;
return U_SUCCESS;
@@ -910,8 +910,8 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
prevItemType = itemType;
result = findNextRawAreaItem(index, itemOffset + prevItemSize, itemType, itemOffset, itemSize, itemAltSize);
- // Silence value not used after assignment warning
- (void)prevItemType;
+ // Silence value not used after assignment warning
+ (void)prevItemType;
}
// Padding at the end of RAW area
@@ -1058,7 +1058,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
UINT32 usedSpace = *(UINT32*)(volume.constData() + 12);
if (appleCrc32 != 0) {
// Calculate CRC32 of the volume body
- UINT32 crc = crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
+ UINT32 crc = (UINT32)crc32(0, (const UINT8*)(volume.constData() + volumeHeader->HeaderLength), volumeSize - volumeHeader->HeaderLength);
if (crc == appleCrc32) {
hasAppleCrc32 = true;
}
@@ -1161,26 +1161,34 @@ USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 l
for (; offset < dataSize - sizeof(UINT32); offset++) {
const UINT32* currentPos = (const UINT32*)(data.constData() + offset);
const UINT32 restSize = dataSize - offset;
- if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION) {// Intel microcode
+ if (readUnaligned(currentPos) == INTEL_MICROCODE_HEADER_VERSION_1) {// Intel microcode
// Check data size
if (restSize < sizeof(INTEL_MICROCODE_HEADER))
continue;
// Check microcode size
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)currentPos;
- if (!INTEL_MICROCODE_HEADER_SIZES_VALID(currentPos) || restSize < ucodeHeader->TotalSize) //TODO: needs a separate checking function
- continue;
// Check reserved bytes
bool reservedBytesValid = true;
for (UINT32 i = 0; i < sizeof(ucodeHeader->Reserved); i++)
- if (ucodeHeader->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) {
+ if (ucodeHeader->Reserved[i] != 0x00) {
reservedBytesValid = false;
break;
}
if (!reservedBytesValid)
continue;
+ // Data size is multiple of 4
+ if (ucodeHeader->DataSize % 4 != 0) {
+ continue;
+ }
+
+ // TotalSize is greater then DataSize and is multiple of 1024
+ if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
+ continue;
+ }
+
// All checks passed, microcode found
nextItemType = Types::Microcode;
nextItemSize = ucodeHeader->TotalSize;
@@ -1442,7 +1450,6 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
if (file.isEmpty()) {
return U_INVALID_PARAMETER;
}
-
if ((UINT32)file.size() < sizeof(EFI_FFS_FILE_HEADER)) {
return U_INVALID_FILE;
}
@@ -1480,14 +1487,16 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
}
UINT32 alignment = (UINT32)(1UL << alignmentPower);
- if ((localOffset + header.size()) % alignment)
+ if ((localOffset + header.size()) % alignment) {
msgUnalignedFile = true;
-
+ }
+
// Check file alignment agains volume alignment
bool msgFileAlignmentIsGreaterThanVolumeAlignment = false;
- if (!isWeakAligned && volumeAlignment < alignment)
+ if (!isWeakAligned && volumeAlignment < alignment) {
msgFileAlignmentIsGreaterThanVolumeAlignment = true;
-
+ }
+
// Get file body
UByteArray body = file.mid(header.size());
@@ -1508,9 +1517,10 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
// Check header checksum
UINT8 calculatedHeader = 0x100 - (calculateSum8((const UINT8*)header.constData(), header.size()) - fileHeader->IntegrityCheck.Checksum.Header - fileHeader->IntegrityCheck.Checksum.File - fileHeader->State);
bool msgInvalidHeaderChecksum = false;
- if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader)
+ if (fileHeader->IntegrityCheck.Checksum.Header != calculatedHeader) {
msgInvalidHeaderChecksum = true;
-
+ }
+
// Check data checksum
// Data checksum must be calculated
bool msgInvalidDataChecksum = false;
@@ -1526,9 +1536,10 @@ USTATUS FfsParser::parseFileHeader(const UByteArray & file, const UINT32 localOf
calculatedData = FFS_FIXED_CHECKSUM2;
}
- if (fileHeader->IntegrityCheck.Checksum.File != calculatedData)
+ if (fileHeader->IntegrityCheck.Checksum.File != calculatedData) {
msgInvalidDataChecksum = true;
-
+ }
+
// Check file type
bool msgUnknownType = false;
if (fileHeader->Type > EFI_FV_FILETYPE_MM_CORE_STANDALONE && fileHeader->Type != EFI_FV_FILETYPE_PAD) {
@@ -1663,19 +1674,16 @@ USTATUS FfsParser::parseFileBody(const UModelIndex & index)
model->setText(index, UString("NVAR store"));
return nvramParser->parseNvarStore(index);
}
-
- if (fileGuid == NVRAM_NVAR_PEI_EXTERNAL_DEFAULTS_FILE_GUID) {
+ else if (fileGuid == NVRAM_NVAR_PEI_EXTERNAL_DEFAULTS_FILE_GUID) {
model->setText(index, UString("NVRAM external defaults"));
return nvramParser->parseNvarStore(index);
}
-
- if (fileGuid == NVRAM_NVAR_BB_DEFAULTS_FILE_GUID) {
+ else if (fileGuid == NVRAM_NVAR_BB_DEFAULTS_FILE_GUID) {
model->setText(index, UString("NVAR bb defaults"));
return nvramParser->parseNvarStore(index);
}
-
// Parse vendor hash file
- if (fileGuid == BG_VENDOR_HASH_FILE_GUID_PHOENIX) {
+ else if (fileGuid == BG_VENDOR_HASH_FILE_GUID_PHOENIX) {
return parseVendorHashFile(fileGuid, index);
}
@@ -2081,7 +2089,7 @@ USTATUS FfsParser::parseGuidedSectionHeader(const UByteArray & section, const UI
UINT32 crc = *(UINT32*)(section.constData() + headerSize);
additionalInfo += UString("\nChecksum type: CRC32");
// Calculate CRC32 of section data
- UINT32 calculated = crc32(0, (const UINT8*)section.constData() + dataOffset, section.size() - dataOffset);
+ UINT32 calculated = (UINT32)crc32(0, (const UINT8*)section.constData() + dataOffset, section.size() - dataOffset);
if (crc == calculated) {
additionalInfo += usprintf("\nChecksum: %08Xh, valid", crc);
}
@@ -2995,6 +3003,9 @@ USTATUS FfsParser::performSecondPass(const UModelIndex & index)
const UINT32 vtfSize = model->header(lastVtf).size() + model->body(lastVtf).size() + model->tail(lastVtf).size();
addressDiff = 0xFFFFFFFFULL - model->base(lastVtf) - vtfSize + 1;
+ // Parse reset vector data
+ parseResetVectorData();
+
// Find and parse FIT
parseFit(index);
@@ -3007,6 +3018,37 @@ USTATUS FfsParser::performSecondPass(const UModelIndex & index)
return U_SUCCESS;
}
+USTATUS FfsParser::parseResetVectorData()
+{
+ // Sanity check
+ if (!lastVtf.isValid())
+ return U_SUCCESS;
+
+ // Check VTF to have enough space at the end to fit Reset Vector Data
+ UByteArray vtf = model->header(lastVtf) + model->body(lastVtf) + model->tail(lastVtf);
+ if ((UINT32)vtf.size() < sizeof(X86_RESET_VECTOR_DATA))
+ return U_SUCCESS;
+
+ const X86_RESET_VECTOR_DATA* resetVectorData = (const X86_RESET_VECTOR_DATA*)(vtf.constData() + vtf.size() - sizeof(X86_RESET_VECTOR_DATA));
+
+ // Add info
+ UString info = usprintf("\nAP entry vector: %02X %02X %02X %02X %02X %02X %02X %02X\n"
+ "Reset vector: %02X %02X %02X %02X %02X %02X %02X %02X\n"
+ "PEI core entry point: %08Xh\n"
+ "AP startup segment: %08X\n"
+ "BootFV base address: %08X\n",
+ resetVectorData->ApEntryVector[0], resetVectorData->ApEntryVector[1], resetVectorData->ApEntryVector[2], resetVectorData->ApEntryVector[3],
+ resetVectorData->ApEntryVector[4], resetVectorData->ApEntryVector[5], resetVectorData->ApEntryVector[6], resetVectorData->ApEntryVector[7],
+ resetVectorData->ResetVector[0], resetVectorData->ResetVector[1], resetVectorData->ResetVector[2], resetVectorData->ResetVector[3],
+ resetVectorData->ResetVector[4], resetVectorData->ResetVector[5], resetVectorData->ResetVector[6], resetVectorData->ResetVector[7],
+ resetVectorData->PeiCoreEntryPoint,
+ resetVectorData->ApStartupSegment,
+ resetVectorData->BootFvBaseAddress);
+
+ model->addInfo(lastVtf, info);
+ return U_SUCCESS;
+}
+
USTATUS FfsParser::checkTeImageBase(const UModelIndex & index)
{
// Sanity check
@@ -3618,13 +3660,13 @@ USTATUS FfsParser::parseFitEntryMicrocode(const UByteArray & microcode, const UI
}
const INTEL_MICROCODE_HEADER* header = (const INTEL_MICROCODE_HEADER*)(microcode.constData() + localOffset);
- if (header->Version != INTEL_MICROCODE_HEADER_VERSION) {
+ if (header->Version != INTEL_MICROCODE_HEADER_VERSION_1) {
return U_INVALID_MICROCODE;
}
bool reservedBytesValid = true;
for (UINT8 i = 0; i < sizeof(header->Reserved); i++)
- if (header->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) {
+ if (header->Reserved[i] != 0x00) {
reservedBytesValid = false;
break;
}
@@ -3632,13 +3674,21 @@ USTATUS FfsParser::parseFitEntryMicrocode(const UByteArray & microcode, const UI
return U_INVALID_MICROCODE;
}
+ if (header->DataSize % 4 != 0) {
+ return U_INVALID_MICROCODE;
+ }
+
+ if (header->TotalSize <= header->DataSize || header->TotalSize % 1024 != 0) {
+ return U_INVALID_MICROCODE;
+ }
+
UINT32 mcSize = header->TotalSize;
if ((UINT32)microcode.size() < localOffset + mcSize) {
return U_INVALID_MICROCODE;
}
// Valid microcode found
- info = usprintf("CPUID: %08Xh, Revision: %08Xh, Date: %02X.%02X.%04X",
+ info = usprintf("CpuSignature: %08Xh, Revision: %08Xh, Date: %02X.%02X.%04X",
header->CpuSignature,
header->Revision,
header->DateDay,
@@ -3678,34 +3728,33 @@ USTATUS FfsParser::parseFitEntryAcm(const UByteArray & acm, const UINT32 localOf
// Add ACM header info
UString acmInfo;
- acmInfo += usprintf(
- " found at base %Xh\n"
- "ModuleType: %04Xh ModuleSubtype: %04Xh HeaderLength: %08Xh\n"
- "HeaderVersion: %08Xh ChipsetId: %04Xh Flags: %04Xh\n"
- "ModuleVendor: %04Xh Date: %02X.%02X.%04X ModuleSize: %08Xh\n"
- "EntryPoint: %08Xh AcmSvn: %04Xh Unknown1: %08Xh\n"
- "Unknown2: %08Xh GdtBase: %08Xh GdtMax: %08Xh\n"
- "SegSel: %08Xh KeySize: %08Xh Unknown3: %08Xh",
- model->base(parent) + localOffset,
- header->ModuleType,
- header->ModuleSubtype,
- header->ModuleSize * sizeof(UINT32),
- header->HeaderVersion,
- header->ChipsetId,
- header->Flags,
- header->ModuleVendor,
- header->DateDay, header->DateMonth, header->DateYear,
- header->ModuleSize * sizeof(UINT32),
- header->EntryPoint,
- header->AcmSvn,
- header->Unknown1,
- header->Unknown2,
- header->GdtBase,
- header->GdtMax,
- header->SegmentSel,
- header->KeySize * sizeof(UINT32),
- header->Unknown4 * sizeof(UINT32)
- );
+ acmInfo += usprintf(" found at base %Xh\n"
+ "ModuleType: %04Xh ModuleSubtype: %04Xh HeaderLength: %08Xh\n"
+ "HeaderVersion: %08Xh ChipsetId: %04Xh Flags: %04Xh\n"
+ "ModuleVendor: %04Xh Date: %02X.%02X.%04X ModuleSize: %08Xh\n"
+ "EntryPoint: %08Xh AcmSvn: %04Xh Unknown1: %08Xh\n"
+ "Unknown2: %08Xh GdtBase: %08Xh GdtMax: %08Xh\n"
+ "SegSel: %08Xh KeySize: %08Xh Unknown3: %08Xh",
+ model->base(parent) + localOffset,
+ header->ModuleType,
+ header->ModuleSubtype,
+ header->ModuleSize * sizeof(UINT32),
+ header->HeaderVersion,
+ header->ChipsetId,
+ header->Flags,
+ header->ModuleVendor,
+ header->DateDay, header->DateMonth, header->DateYear,
+ header->ModuleSize * sizeof(UINT32),
+ header->EntryPoint,
+ header->AcmSvn,
+ header->Unknown1,
+ header->Unknown2,
+ header->GdtBase,
+ header->GdtMax,
+ header->SegmentSel,
+ header->KeySize * sizeof(UINT32),
+ header->Unknown4 * sizeof(UINT32)
+ );
// Add PubKey
acmInfo += usprintf("\n\nACM RSA Public Key (Exponent: %Xh):", header->RsaPubExp);
for (UINT16 i = 0; i < sizeof(header->RsaPubKey); i++) {
@@ -4071,66 +4120,134 @@ USTATUS FfsParser::parseMicrocodeVolumeBody(const UModelIndex & index)
USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
{
- const UINT32 dataSize = (const UINT32)microcode.size();
-
- if (dataSize < sizeof(INTEL_MICROCODE_HEADER)) {
- //msg(usprintf("%s: input is too small even for Intel microcode header", __FUNCTION__), parent);
+ // We have enough data to fit the header
+ if ((UINT32)microcode.size() < sizeof(INTEL_MICROCODE_HEADER)) {
return U_INVALID_MICROCODE;
}
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)microcode.constData();
- if (ucodeHeader->Version != INTEL_MICROCODE_HEADER_VERSION) {
- //msg(usprintf("%s: input has invalid Intel microcode header", __FUNCTION__), parent);
- return U_INVALID_MICROCODE;
- }
-
- if (!INTEL_MICROCODE_HEADER_SIZES_VALID(ucodeHeader)) {
- //msg(usprintf("%s: input has invalid Intel microcode header", __FUNCTION__), parent);
+
+ // Header version is 1
+ if (ucodeHeader->Version != INTEL_MICROCODE_HEADER_VERSION_1) {
return U_INVALID_MICROCODE;
}
+ // Reserved bytes are all zeroes
bool reservedBytesValid = true;
- for (UINT8 i = 0; i < sizeof(ucodeHeader->Reserved); i++)
- if (ucodeHeader->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) {
+ for (UINT8 i = 0; i < sizeof(ucodeHeader->Reserved); i++) {
+ if (ucodeHeader->Reserved[i] != 0x00) {
reservedBytesValid = false;
break;
}
+ }
if (!reservedBytesValid) {
- //msg(usprintf("%s: input has invalid Intel microcode header", __FUNCTION__), parent);
return U_INVALID_MICROCODE;
}
- if (dataSize < ucodeHeader->TotalSize) {
- //msg(usprintf("%s: input is too small for the whole Intel microcode", __FUNCTION__), parent);
+ // Data size is multiple of 4
+ if (ucodeHeader->DataSize % 4 != 0) {
+ return U_INVALID_MICROCODE;
+ }
+
+ // TotalSize is greater then DataSize and is multiple of 1024
+ if (ucodeHeader->TotalSize <= ucodeHeader->DataSize || ucodeHeader->TotalSize % 1024 != 0) {
+ return U_INVALID_MICROCODE;
+ }
+
+ // We have enough data to fit the whole TotalSize
+ if ((UINT32)microcode.size() < ucodeHeader->TotalSize) {
return U_INVALID_MICROCODE;
}
// Valid microcode found
- // Construct header and body
+ UINT32 dataSize = ucodeHeader->DataSize;
+ if (dataSize == 0)
+ dataSize = INTEL_MICROCODE_REAL_DATA_SIZE_ON_ZERO;
+
+ // Recalculate the whole microcode checksum
+ UByteArray tempMicrocode = microcode;
+ INTEL_MICROCODE_HEADER* tempUcodeHeader = (INTEL_MICROCODE_HEADER*)(tempMicrocode.data());
+ tempUcodeHeader->Checksum = 0;
+ UINT32 calculated = calculateChecksum32((const UINT32*)tempMicrocode.constData(), tempUcodeHeader->TotalSize);
+ bool msgInvalidChecksum = (ucodeHeader->Checksum != calculated);
+
+ // Construct header, body and tail
UByteArray header = microcode.left(sizeof(INTEL_MICROCODE_HEADER));
- UByteArray body = microcode.mid(sizeof(INTEL_MICROCODE_HEADER), ucodeHeader->DataSize);
-
- //TODO: recalculate microcode checksum
-
+ UByteArray body = microcode.mid(sizeof(INTEL_MICROCODE_HEADER), dataSize);
+ UByteArray tail = microcode.mid(sizeof(INTEL_MICROCODE_HEADER) + dataSize);
+
+ // Check if we have extended header in the tail
+ UString extendedHeaderInfo;
+ if ((UINT32)tail.size() >= sizeof(INTEL_MICROCODE_EXTENDED_HEADER)) {
+ const INTEL_MICROCODE_EXTENDED_HEADER* extendedHeader = (const INTEL_MICROCODE_EXTENDED_HEADER*)tail.constData();
+
+ // Reserved bytes are all zeroes
+ bool extendedReservedBytesValid = true;
+ for (UINT8 i = 0; i < sizeof(extendedHeader->Reserved); i++) {
+ if (extendedHeader->Reserved[i] != 0x00) {
+ extendedReservedBytesValid = false;
+ break;
+ }
+ }
+
+ // We have more than 0 entries and they are all in the tail
+ if (extendedReservedBytesValid
+ && extendedHeader->EntryCount > 0
+ && (UINT32)tail.size() >= sizeof(INTEL_MICROCODE_EXTENDED_HEADER) + extendedHeader->EntryCount * sizeof(INTEL_MICROCODE_EXTENDED_HEADER_ENTRY)) {
+ // Recalculate extended header checksum
+ INTEL_MICROCODE_EXTENDED_HEADER* tempExtendedHeader = (INTEL_MICROCODE_EXTENDED_HEADER*)(tempMicrocode.data() + sizeof(INTEL_MICROCODE_HEADER) + dataSize);
+ tempExtendedHeader->Checksum = 0;
+ UINT32 extendedCalculated = calculateChecksum32((const UINT32*)tempExtendedHeader, sizeof(INTEL_MICROCODE_EXTENDED_HEADER) + extendedHeader->EntryCount * sizeof(INTEL_MICROCODE_EXTENDED_HEADER_ENTRY));
+
+ extendedHeaderInfo = usprintf("\nExtended header entries: %u\nExtended header checksum: %08Xh, ",
+ extendedHeader->EntryCount,
+ extendedHeader->Checksum)
+ + (extendedHeader->Checksum == extendedCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", extendedCalculated));
+
+ const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY* firstEntry = (const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY*)(extendedHeader + 1);
+ for (UINT8 i = 0; i < extendedHeader->EntryCount; i++) {
+ const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY* entry = (const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY*)(firstEntry + i);
+
+ // Recalculate checksum after patching
+ tempUcodeHeader->Checksum = 0;
+ tempUcodeHeader->CpuFlags = entry->CpuFlags;
+ tempUcodeHeader->CpuSignature = entry->CpuSignature;
+ UINT32 entryCalculated = calculateChecksum32((const UINT32*)tempMicrocode.constData(), sizeof(INTEL_MICROCODE_HEADER) + dataSize);
+
+
+ extendedHeaderInfo += usprintf("\nCPU signature #%u: %08Xh\nCPU flags #%u: %08Xh\nChecksum #%u: %08Xh, ",
+ i + 1, entry->CpuSignature,
+ i + 1, entry->CpuFlags,
+ i + 1, entry->Checksum)
+ + (entry->Checksum == entryCalculated ? UString("valid") : usprintf("invalid, should be %08Xh", entryCalculated));
+ }
+ }
+ }
+
// Add info
UString name("Intel microcode");
- UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\n"
- "Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nChecksum: %08Xh\nLoader revision: %08Xh\nCPU flags: %08Xh",
- ucodeHeader->TotalSize, ucodeHeader->TotalSize,
- header.size(), header.size(),
- body.size(), body.size(),
- ucodeHeader->DateDay,
- ucodeHeader->DateMonth,
- ucodeHeader->DateYear,
- ucodeHeader->CpuSignature,
- ucodeHeader->Revision,
- ucodeHeader->Checksum,
- ucodeHeader->LoaderRevision,
- ucodeHeader->CpuFlags);
-
+ UString info = usprintf("Full size: %Xh (%u)\nHeader size: %Xh (%u)\nBody size: %Xh (%u)\nTail size: %Xh (%u)\n"
+ "Date: %02X.%02X.%04x\nCPU signature: %08Xh\nRevision: %08Xh\nLoader revision: %08Xh\nCPU flags: %08Xh\nChecksum: %08Xh, ",
+ dataSize, dataSize,
+ header.size(), header.size(),
+ body.size(), body.size(),
+ tail.size(), tail.size(),
+ ucodeHeader->DateDay,
+ ucodeHeader->DateMonth,
+ ucodeHeader->DateYear,
+ ucodeHeader->CpuSignature,
+ ucodeHeader->Revision,
+ ucodeHeader->LoaderRevision,
+ ucodeHeader->CpuFlags,
+ ucodeHeader->Checksum)
+ + (ucodeHeader->Checksum == calculated ? UString("valid") : usprintf("invalid, should be %08Xh", calculated))
+ + extendedHeaderInfo;
+
// Add tree item
- index = model->addItem(localOffset, Types::Microcode, Subtypes::IntelMicrocode, name, UString(), info, header, body, UByteArray(), Fixed, parent);
-
- // No need to parse body further for now
+ index = model->addItem(localOffset, Types::Microcode, Subtypes::IntelMicrocode, name, UString(), info, header, body, tail, Fixed, parent);
+ if (msgInvalidChecksum)
+ msg(usprintf("%s: invalid microcode checksum %08Xh, should be %08Xh", __FUNCTION__, ucodeHeader->Checksum, calculated), index);
+
+ // No need to parse the body further for now
return U_SUCCESS;
}
diff --git a/common/ffsparser.h b/common/ffsparser.h
index 0ab735a..74febfc 100644
--- a/common/ffsparser.h
+++ b/common/ffsparser.h
@@ -144,6 +144,7 @@ private:
USTATUS checkProtectedRanges(const UModelIndex & index);
USTATUS markProtectedRangeRecursive(const UModelIndex & index, const BG_PROTECTED_RANGE & range);
+ USTATUS parseResetVectorData();
USTATUS parseFit(const UModelIndex & index);
USTATUS parseVendorHashFile(const UByteArray & fileGuid, const UModelIndex & index);
USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
diff --git a/common/ffsreport.cpp b/common/ffsreport.cpp
index cf94860..6f06745 100644
--- a/common/ffsreport.cpp
+++ b/common/ffsreport.cpp
@@ -49,7 +49,7 @@ USTATUS FfsReport::generateRecursive(std::vector & report, const UModel
// Calculate item CRC32
UByteArray data = model->header(index) + model->body(index) + model->tail(index);
- UINT32 crc = crc32(0, (const UINT8*)data.constData(), data.size());
+ UINT32 crc = (UINT32)crc32(0, (const UINT8*)data.constData(), data.size());
// Information on current item
UString text = model->text(index);
diff --git a/common/fit.h b/common/fit.h
old mode 100644
new mode 100755
index 24a79ff..afa98bd
--- a/common/fit.h
+++ b/common/fit.h
@@ -50,21 +50,6 @@ typedef struct FIT_ENTRY_ {
UINT8 Checksum;
} FIT_ENTRY;
-typedef struct INTEL_MICROCODE_HEADER_ {
- UINT32 Version;
- UINT32 Revision;
- UINT16 DateYear;
- UINT8 DateDay;
- UINT8 DateMonth;
- UINT32 CpuSignature;
- UINT32 Checksum;
- UINT32 LoaderRevision;
- UINT32 CpuFlags;
- UINT32 DataSize;
- UINT32 TotalSize;
- UINT8 Reserved[12];
-} INTEL_MICROCODE_HEADER;
-
typedef struct {
UINT16 IndexRegisterAddress;
UINT16 DataRegisterAddress;
@@ -73,9 +58,51 @@ typedef struct {
UINT16 Index;
} FIT_ENTRY_VERSION_0_CONFIG_POLICY;
-#define INTEL_MICROCODE_HEADER_VERSION 0x00000001
-#define INTEL_MICROCODE_HEADER_RESERVED_BYTE 0x00
-#define INTEL_MICROCODE_HEADER_SIZES_VALID(ptr) (((INTEL_MICROCODE_HEADER*)ptr)->TotalSize - ((INTEL_MICROCODE_HEADER*)ptr)->DataSize == sizeof(INTEL_MICROCODE_HEADER))
+// This scructure is described in Section 9.11.1 of the Intel Software Developer manual Volume 3A Part 1
+typedef struct INTEL_MICROCODE_HEADER_ {
+ UINT32 Version;
+ UINT32 Revision;
+ UINT16 DateYear;
+ UINT8 DateDay;
+ UINT8 DateMonth;
+ UINT32 CpuSignature;
+ UINT32 Checksum; // Checksum of Update Data and Header. Used to verify the integrity of the update header and data.
+ // Checksum is correct when the summation of all the DWORDs (including the extended Processor Signature Table)
+ // that comprise the microcode update result in 00000000H.
+
+ UINT32 LoaderRevision;
+ UINT32 CpuFlags;
+ UINT32 DataSize; // Specifies the size of the encrypted data in bytes, and must be a multiple of DWORDs.
+ // If this value is 00000000H, then the microcode update encrypted data is 2000 bytes (or 500 DWORDs).
+
+ UINT32 TotalSize;// Specifies the total size of the microcode update in bytes.
+ // It is the summation of the header size, the encrypted data size and the size of the optional extended signature table.
+ // This value is always a multiple of 1024.
+
+ UINT8 Reserved[12];
+} INTEL_MICROCODE_HEADER;
+
+#define INTEL_MICROCODE_REAL_DATA_SIZE_ON_ZERO 2000
+
+typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ {
+ UINT32 EntryCount;
+ UINT32 Checksum; // Checksum of extended processor signature table.
+ // Used to verify the integrity of the extended processor signature table.
+ // Checksum is correct when the summation of the DWORDs that comprise the extended processor signature table results in 00000000H.
+
+ UINT8 Reserved[12];
+ // INTEL_MICROCODE_EXTENDED_HEADER_ENTRY Entries[EntryCount];
+} INTEL_MICROCODE_EXTENDED_HEADER;
+
+typedef struct INTEL_MICROCODE_EXTENDED_HEADER_ENTRY_ {
+ UINT32 CpuSignature;
+ UINT32 CpuFlags;
+ UINT32 Checksum; // To calculate the Checksum, substitute the Primary Processor Signature entry and the Processor Flags entry with the corresponding Extended Patch entry.
+ // Delete the Extended Processor Signature Table entries.
+ // Checksum is correct when the summation of all DWORDs that comprise the created Extended Processor Patch results in 00000000H.
+} INTEL_MICROCODE_EXTENDED_HEADER_ENTRY;
+
+#define INTEL_MICROCODE_HEADER_VERSION_1 0x00000001
#pragma pack(pop)
diff --git a/common/meparser.cpp b/common/meparser.cpp
new file mode 100755
index 0000000..b7ae12f
--- /dev/null
+++ b/common/meparser.cpp
@@ -0,0 +1,1169 @@
+/* meparser.cpp
+
+Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+*/
+
+#include
+#include