mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-24 17:08:23 +08:00
Display microcode in the tree
This commit is contained in:
parent
717821de2b
commit
2d02eeab6d
3
.gitignore
vendored
3
.gitignore
vendored
@ -3,6 +3,7 @@
|
|||||||
#################
|
#################
|
||||||
moc_*.*
|
moc_*.*
|
||||||
ui_*.*
|
ui_*.*
|
||||||
|
qrc_*.*
|
||||||
|
|
||||||
#################
|
#################
|
||||||
## Qt Creator
|
## Qt Creator
|
||||||
@ -234,6 +235,8 @@ Makefile
|
|||||||
|
|
||||||
uefitool_plugin_import.cpp
|
uefitool_plugin_import.cpp
|
||||||
UEFITool.app/
|
UEFITool.app/
|
||||||
|
UEFITool/Info.plist
|
||||||
|
UEFITool/XCBuildData
|
||||||
UEFIDump/UEFIDump
|
UEFIDump/UEFIDump
|
||||||
UEFIExtract/UEFIExtract
|
UEFIExtract/UEFIExtract
|
||||||
UEFIFind/UEFIFind
|
UEFIFind/UEFIFind
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* ffsdumper.cpp
|
/* ffsdumper.cpp
|
||||||
|
|
||||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
Copyright (c) 2018, LongSoft. All rights reserved.
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* uefidump.h
|
/* uefidump.h
|
||||||
|
|
||||||
Copyright (c) 2016, Nikolaj Schlej. All rights reserved.
|
Copyright (c) 2018, LongSoft. All rights reserved.
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
|
0
UEFITool/ffsfinder.cpp
Normal file → Executable file
0
UEFITool/ffsfinder.cpp
Normal file → Executable file
0
UEFITool/ffsfinder.h
Normal file → Executable file
0
UEFITool/ffsfinder.h
Normal file → Executable file
@ -112,7 +112,7 @@ int QHexEdit::addressWidth()
|
|||||||
if (size > Q_INT64_C(0x100000000)){ n += 8; size /= Q_INT64_C(0x100000000);}
|
if (size > Q_INT64_C(0x100000000)){ n += 8; size /= Q_INT64_C(0x100000000);}
|
||||||
if (size > 0x10000){ n += 4; size /= 0x10000;}
|
if (size > 0x10000){ n += 4; size /= 0x10000;}
|
||||||
if (size > 0x100){ n += 2; size /= 0x100;}
|
if (size > 0x100){ n += 2; size /= 0x100;}
|
||||||
if (size > 0x10){ n += 1; size /= 0x10;}
|
if (size > 0x10){ n += 1; }
|
||||||
|
|
||||||
if (n > _addressWidth)
|
if (n > _addressWidth)
|
||||||
return n;
|
return n;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -114,7 +114,6 @@ void UEFITool::init()
|
|||||||
ui->infoEdit->clear();
|
ui->infoEdit->clear();
|
||||||
ui->bootGuardEdit->clear();
|
ui->bootGuardEdit->clear();
|
||||||
ui->txtEdit->clear();
|
ui->txtEdit->clear();
|
||||||
ui->microcodeEdit->clear();
|
|
||||||
ui->messagesTabWidget->setTabEnabled(1, false);
|
ui->messagesTabWidget->setTabEnabled(1, false);
|
||||||
ui->messagesTabWidget->setTabEnabled(2, false);
|
ui->messagesTabWidget->setTabEnabled(2, false);
|
||||||
ui->messagesTabWidget->setTabEnabled(3, false);
|
ui->messagesTabWidget->setTabEnabled(3, false);
|
||||||
@ -201,7 +200,8 @@ void UEFITool::populateUi(const UModelIndex ¤t)
|
|||||||
ui->menuVolumeActions->setEnabled(type == Types::Volume);
|
ui->menuVolumeActions->setEnabled(type == Types::Volume);
|
||||||
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->menuEntryActions->setEnabled(type == Types::NvarEntry
|
ui->menuEntryActions->setEnabled(type == Types::Microcode
|
||||||
|
|| type == Types::NvarEntry
|
||||||
|| type == Types::VssEntry
|
|| type == Types::VssEntry
|
||||||
|| type == Types::FsysEntry
|
|| type == Types::FsysEntry
|
||||||
|| type == Types::EvsaEntry
|
|| type == Types::EvsaEntry
|
||||||
@ -214,8 +214,8 @@ void UEFITool::populateUi(const UModelIndex ¤t)
|
|||||||
|| type == Types::FtwStore
|
|| type == Types::FtwStore
|
||||||
|| type == Types::FlashMapStore
|
|| type == Types::FlashMapStore
|
||||||
|| type == Types::CmdbStore
|
|| type == Types::CmdbStore
|
||||||
|| type == Types::Microcode
|
|| type == Types::SlicData
|
||||||
|| type == Types::SlicData);
|
);
|
||||||
|
|
||||||
// Enable actions
|
// Enable actions
|
||||||
ui->actionHexView->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
|
ui->actionHexView->setDisabled(model->hasEmptyHeader(current) && model->hasEmptyBody(current) && model->hasEmptyTail(current));
|
||||||
@ -700,18 +700,6 @@ void UEFITool::extract(const UINT8 mode, UString* pathOut)
|
|||||||
|| subtype == EFI_SECTION_PIC) path = QFileDialog::getSaveFileName(this, tr("Save section body to EFI executable file"), name + ".efi", tr("EFI executable files (*.efi *.bin);;All files (*)"));
|
|| subtype == EFI_SECTION_PIC) path = QFileDialog::getSaveFileName(this, tr("Save section body to EFI executable file"), name + ".efi", tr("EFI executable files (*.efi *.bin);;All files (*)"));
|
||||||
else path = QFileDialog::getSaveFileName(this, tr("Save section body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)"));
|
else path = QFileDialog::getSaveFileName(this, tr("Save section body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)"));
|
||||||
break;
|
break;
|
||||||
case Types::NvarEntry:
|
|
||||||
case Types::VssEntry:
|
|
||||||
case Types::EvsaEntry:
|
|
||||||
case Types::FlashMapEntry:
|
|
||||||
case Types::FsysEntry: path = QFileDialog::getSaveFileName(this, tr("Save entry body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); break;
|
|
||||||
case Types::VssStore:
|
|
||||||
case Types::Vss2Store:
|
|
||||||
case Types::FtwStore:
|
|
||||||
case Types::FdcStore:
|
|
||||||
case Types::FsysStore:
|
|
||||||
case Types::FlashMapStore:
|
|
||||||
case Types::CmdbStore: path = QFileDialog::getSaveFileName(this, tr("Save store body to file"), name + ".bin", tr("Binary files (*.bin);;All files (*)")); break;
|
|
||||||
case Types::Microcode: path = QFileDialog::getSaveFileName(this, tr("Save microcode body to file"), name + ".ucb", tr("Microcode body files (*.ucb *.bin);;All files (*)")); break;
|
case Types::Microcode: path = QFileDialog::getSaveFileName(this, tr("Save microcode body to file"), name + ".ucb", tr("Microcode body files (*.ucb *.bin);;All files (*)")); break;
|
||||||
case Types::SlicData:
|
case Types::SlicData:
|
||||||
if (subtype == Subtypes::PubkeySlicData) path = QFileDialog::getSaveFileName(this, tr("Save SLIC pubkey body to file"), name + ".spb", tr("SLIC pubkey body files (*.spb *.bin);;All files (*)"));
|
if (subtype == Subtypes::PubkeySlicData) path = QFileDialog::getSaveFileName(this, tr("Save SLIC pubkey body to file"), name + ".spb", tr("SLIC pubkey body files (*.spb *.bin);;All files (*)"));
|
||||||
@ -1151,11 +1139,6 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
|
|||||||
case Types::Volume: ui->menuVolumeActions->exec(event->globalPos()); break;
|
case Types::Volume: ui->menuVolumeActions->exec(event->globalPos()); break;
|
||||||
case Types::File: ui->menuFileActions->exec(event->globalPos()); break;
|
case Types::File: ui->menuFileActions->exec(event->globalPos()); break;
|
||||||
case Types::Section: ui->menuSectionActions->exec(event->globalPos()); break;
|
case Types::Section: ui->menuSectionActions->exec(event->globalPos()); break;
|
||||||
case Types::NvarEntry:
|
|
||||||
case Types::VssEntry:
|
|
||||||
case Types::FsysEntry:
|
|
||||||
case Types::EvsaEntry:
|
|
||||||
case Types::FlashMapEntry: ui->menuEntryActions->exec(event->globalPos()); break;
|
|
||||||
case Types::VssStore:
|
case Types::VssStore:
|
||||||
case Types::Vss2Store:
|
case Types::Vss2Store:
|
||||||
case Types::FdcStore:
|
case Types::FdcStore:
|
||||||
@ -1163,9 +1146,8 @@ void UEFITool::contextMenuEvent(QContextMenuEvent* event)
|
|||||||
case Types::EvsaStore:
|
case Types::EvsaStore:
|
||||||
case Types::FtwStore:
|
case Types::FtwStore:
|
||||||
case Types::FlashMapStore:
|
case Types::FlashMapStore:
|
||||||
case Types::CmdbStore:
|
case Types::CmdbStore: ui->menuStoreActions->exec(event->globalPos()); break;
|
||||||
case Types::Microcode:
|
default: ui->menuEntryActions->exec(event->globalPos()); break;
|
||||||
case Types::SlicData: ui->menuStoreActions->exec(event->globalPos()); break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1213,7 +1195,6 @@ void UEFITool::readSettings()
|
|||||||
ui->fitTableWidget->setFont(currentFont);
|
ui->fitTableWidget->setFont(currentFont);
|
||||||
ui->bootGuardEdit->setFont(currentFont);
|
ui->bootGuardEdit->setFont(currentFont);
|
||||||
ui->txtEdit->setFont(currentFont);
|
ui->txtEdit->setFont(currentFont);
|
||||||
ui->microcodeEdit->setFont(currentFont);
|
|
||||||
ui->structureTreeView->setFont(currentFont);
|
ui->structureTreeView->setFont(currentFont);
|
||||||
searchDialog->ui->guidEdit->setFont(currentFont);
|
searchDialog->ui->guidEdit->setFont(currentFont);
|
||||||
searchDialog->ui->hexEdit->setFont(currentFont);
|
searchDialog->ui->hexEdit->setFont(currentFont);
|
||||||
@ -1287,14 +1268,6 @@ void UEFITool::showFitTable()
|
|||||||
ui->messagesTabWidget->setCurrentIndex(2);
|
ui->messagesTabWidget->setCurrentIndex(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get Microcode info
|
|
||||||
UString microcodeInfo = ffsParser->getMicrocodeInfo();
|
|
||||||
if (!microcodeInfo.isEmpty()) {
|
|
||||||
ui->messagesTabWidget->setTabEnabled(4, true);
|
|
||||||
ui->microcodeEdit->setPlainText(microcodeInfo);
|
|
||||||
ui->messagesTabWidget->setCurrentIndex(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get TXT ACM info
|
// Get TXT ACM info
|
||||||
UString txtInfo = ffsParser->getTxtInfo();
|
UString txtInfo = ffsParser->getTxtInfo();
|
||||||
if (!txtInfo.isEmpty()) {
|
if (!txtInfo.isEmpty()) {
|
||||||
|
@ -279,44 +279,6 @@
|
|||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QWidget" name="microcodeTab">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
<attribute name="title">
|
|
||||||
<string>Microcode</string>
|
|
||||||
</attribute>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
|
||||||
<property name="spacing">
|
|
||||||
<number>0</number>
|
|
||||||
</property>
|
|
||||||
<property name="leftMargin">
|
|
||||||
<number>5</number>
|
|
||||||
</property>
|
|
||||||
<property name="topMargin">
|
|
||||||
<number>5</number>
|
|
||||||
</property>
|
|
||||||
<property name="rightMargin">
|
|
||||||
<number>5</number>
|
|
||||||
</property>
|
|
||||||
<property name="bottomMargin">
|
|
||||||
<number>5</number>
|
|
||||||
</property>
|
|
||||||
<item>
|
|
||||||
<widget class="QPlainTextEdit" name="microcodeEdit">
|
|
||||||
<property name="acceptDrops">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="undoRedoEnabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="readOnly">
|
|
||||||
<bool>true</bool>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<widget class="QWidget" name="finderTab">
|
<widget class="QWidget" name="finderTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Search</string>
|
<string>Search</string>
|
||||||
|
@ -17,8 +17,8 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
const UByteArray FFSv2VolumesInt[] = {
|
const UByteArray FFSv2VolumesInt[] = {
|
||||||
EFI_FIRMWARE_FILE_SYSTEM_GUID,
|
EFI_FIRMWARE_FILE_SYSTEM_GUID,
|
||||||
EFI_FIRMWARE_FILE_SYSTEM2_GUID,
|
EFI_FIRMWARE_FILE_SYSTEM2_GUID,
|
||||||
EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM_GUID,
|
EFI_APPLE_AUTHENTICATION_FV_GUID,
|
||||||
EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM2_GUID,
|
EFI_APPLE_IMMUTABLE_FV_GUID,
|
||||||
EFI_INTEL_FILE_SYSTEM_GUID,
|
EFI_INTEL_FILE_SYSTEM_GUID,
|
||||||
EFI_INTEL_FILE_SYSTEM2_GUID,
|
EFI_INTEL_FILE_SYSTEM2_GUID,
|
||||||
EFI_SONY_FILE_SYSTEM_GUID
|
EFI_SONY_FILE_SYSTEM_GUID
|
||||||
|
49
common/ffs.h
49
common/ffs.h
@ -114,38 +114,43 @@ typedef struct EFI_FIRMWARE_VOLUME_HEADER_ {
|
|||||||
} EFI_FIRMWARE_VOLUME_HEADER;
|
} EFI_FIRMWARE_VOLUME_HEADER;
|
||||||
|
|
||||||
// Standard file system GUIDs
|
// Standard file system GUIDs
|
||||||
const UByteArray EFI_FIRMWARE_FILE_SYSTEM_GUID
|
const UByteArray EFI_FIRMWARE_FILE_SYSTEM_GUID // 7A9354D9-0468-444A-81CE-0BF617D890DF
|
||||||
("\xD9\x54\x93\x7A\x68\x04\x4A\x44\x81\xCE\x0B\xF6\x17\xD8\x90\xDF", 16);
|
("\xD9\x54\x93\x7A\x68\x04\x4A\x44\x81\xCE\x0B\xF6\x17\xD8\x90\xDF", 16);
|
||||||
const UByteArray EFI_FIRMWARE_FILE_SYSTEM2_GUID
|
|
||||||
|
const UByteArray EFI_FIRMWARE_FILE_SYSTEM2_GUID // 8C8CE578-8A3D-4F1C-9935-896185C32DD3
|
||||||
("\x78\xE5\x8C\x8C\x3D\x8A\x1C\x4F\x99\x35\x89\x61\x85\xC3\x2D\xD3", 16);
|
("\x78\xE5\x8C\x8C\x3D\x8A\x1C\x4F\x99\x35\x89\x61\x85\xC3\x2D\xD3", 16);
|
||||||
// Vendor-specific file system GUIDs
|
|
||||||
const UByteArray EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM_GUID
|
|
||||||
("\xAD\xEE\xAD\x04\xFF\x61\x31\x4D\xB6\xBA\x64\xF8\xBF\x90\x1F\x5A", 16);
|
|
||||||
const UByteArray EFI_APPLE_BOOT_VOLUME_FILE_SYSTEM2_GUID
|
|
||||||
("\x8C\x1B\x00\xBD\x71\x6A\x7B\x48\xA1\x4F\x0C\x2A\x2D\xCF\x7A\x5D", 16);
|
|
||||||
|
|
||||||
// AD3FFFFF-D28B-44C4-9F13-9EA98A97F9F0 // Intel 1
|
|
||||||
const UByteArray EFI_INTEL_FILE_SYSTEM_GUID
|
|
||||||
("\xFF\xFF\x3F\xAD\x8B\xD2\xC4\x44\x9F\x13\x9E\xA9\x8A\x97\xF9\xF0", 16);
|
|
||||||
// D6A1CD70-4B33-4994-A6EA-375F2CCC5437 // Intel 2
|
|
||||||
const UByteArray EFI_INTEL_FILE_SYSTEM2_GUID
|
|
||||||
("\x70\xCD\xA1\xD6\x33\x4B\x94\x49\xA6\xEA\x37\x5F\x2C\xCC\x54\x37", 16);
|
|
||||||
// 4F494156-AED6-4D64-A537-B8A5557BCEEC // Sony 1
|
|
||||||
const UByteArray EFI_SONY_FILE_SYSTEM_GUID
|
|
||||||
("\x56\x41\x49\x4F\xD6\xAE\x64\x4D\xA5\x37\xB8\xA5\x55\x7B\xCE\xEC", 16);
|
|
||||||
|
|
||||||
|
|
||||||
// Vector of volume GUIDs with FFSv2-compatible files
|
|
||||||
extern const std::vector<UByteArray> FFSv2Volumes;
|
|
||||||
|
|
||||||
const UByteArray EFI_FIRMWARE_FILE_SYSTEM3_GUID // 5473C07A-3DCB-4DCA-BD6F-1E9689E7349A
|
const UByteArray EFI_FIRMWARE_FILE_SYSTEM3_GUID // 5473C07A-3DCB-4DCA-BD6F-1E9689E7349A
|
||||||
("\x7A\xC0\x73\x54\xCB\x3D\xCA\x4D\xBD\x6F\x1E\x96\x89\xE7\x34\x9A", 16);
|
("\x7A\xC0\x73\x54\xCB\x3D\xCA\x4D\xBD\x6F\x1E\x96\x89\xE7\x34\x9A", 16);
|
||||||
|
|
||||||
|
// Vendor-specific file system GUIDs
|
||||||
|
const UByteArray EFI_APPLE_IMMUTABLE_FV_GUID // 04ADEEAD-61FF-4D31-B6BA-64F8BF901F5A
|
||||||
|
("\xAD\xEE\xAD\x04\xFF\x61\x31\x4D\xB6\xBA\x64\xF8\xBF\x90\x1F\x5A", 16);
|
||||||
|
|
||||||
|
const UByteArray EFI_APPLE_AUTHENTICATION_FV_GUID // BD001B8C-6A71-487B-A14F-0C2A2DCF7A5D
|
||||||
|
("\x8C\x1B\x00\xBD\x71\x6A\x7B\x48\xA1\x4F\x0C\x2A\x2D\xCF\x7A\x5D", 16);
|
||||||
|
|
||||||
|
const UByteArray EFI_APPLE_MICROCODE_VOLUME_GUID // 153D2197-29BD-44DC-AC59-887F70E41A6B
|
||||||
|
("\x97\x21\x3D\x15\xBD\x29\xDC\x44\xAC\x59\x88\x7F\x70\xE4\x1A\x6B", 16);
|
||||||
|
#define EFI_APPLE_MICROCODE_VOLUME_HEADER_SIZE 0x100
|
||||||
|
|
||||||
|
const UByteArray EFI_INTEL_FILE_SYSTEM_GUID // AD3FFFFF-D28B-44C4-9F13-9EA98A97F9F0
|
||||||
|
("\xFF\xFF\x3F\xAD\x8B\xD2\xC4\x44\x9F\x13\x9E\xA9\x8A\x97\xF9\xF0", 16);
|
||||||
|
|
||||||
|
const UByteArray EFI_INTEL_FILE_SYSTEM2_GUID // D6A1CD70-4B33-4994-A6EA-375F2CCC5437
|
||||||
|
("\x70\xCD\xA1\xD6\x33\x4B\x94\x49\xA6\xEA\x37\x5F\x2C\xCC\x54\x37", 16);
|
||||||
|
|
||||||
|
const UByteArray EFI_SONY_FILE_SYSTEM_GUID // 4F494156-AED6-4D64-A537-B8A5557BCEEC
|
||||||
|
("\x56\x41\x49\x4F\xD6\xAE\x64\x4D\xA5\x37\xB8\xA5\x55\x7B\xCE\xEC", 16);
|
||||||
|
|
||||||
|
// Vector of volume GUIDs with FFSv2-compatible files
|
||||||
|
extern const std::vector<UByteArray> FFSv2Volumes;
|
||||||
|
|
||||||
// Vector of volume GUIDs with FFSv3-compatible files
|
// Vector of volume GUIDs with FFSv3-compatible files
|
||||||
extern const std::vector<UByteArray> FFSv3Volumes;
|
extern const std::vector<UByteArray> FFSv3Volumes;
|
||||||
|
|
||||||
// Firmware volume signature
|
// Firmware volume signature
|
||||||
const UByteArray EFI_FV_SIGNATURE("_FVH", 4);
|
#define EFI_FV_SIGNATURE 0x4856465F // _FVH
|
||||||
#define EFI_FV_SIGNATURE_OFFSET 0x28
|
#define EFI_FV_SIGNATURE_OFFSET 0x28
|
||||||
|
|
||||||
// Firmware volume attributes
|
// Firmware volume attributes
|
||||||
|
@ -109,8 +109,10 @@ USTATUS FfsParser::performFirstPass(const UByteArray & buffer, UModelIndex & ind
|
|||||||
return EFI_INVALID_PARAMETER;
|
return EFI_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
USTATUS result;
|
||||||
|
|
||||||
// Try parsing as UEFI Capsule
|
// Try parsing as UEFI Capsule
|
||||||
USTATUS result = parseCapsule(buffer, index);
|
result = parseCapsule(buffer, 0, UModelIndex(), index);;
|
||||||
if (result != U_ITEM_NOT_FOUND) {
|
if (result != U_ITEM_NOT_FOUND) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -122,6 +124,7 @@ USTATUS FfsParser::performFirstPass(const UByteArray & buffer, UModelIndex & ind
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Parse as generic image
|
// Parse as generic image
|
||||||
|
imageBase = 0;
|
||||||
return parseGenericImage(buffer, 0, UModelIndex(), index);
|
return parseGenericImage(buffer, 0, UModelIndex(), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,7 +141,7 @@ USTATUS FfsParser::parseGenericImage(const UByteArray & buffer, const UINT32 loc
|
|||||||
return parseRawArea(index);
|
return parseRawArea(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::parseCapsule(const UByteArray & capsule, UModelIndex & index)
|
USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||||
{
|
{
|
||||||
// Check buffer size to be more than or equal to size of EFI_CAPSULE_HEADER
|
// Check buffer size to be more than or equal to size of EFI_CAPSULE_HEADER
|
||||||
if ((UINT32)capsule.size() < sizeof(EFI_CAPSULE_HEADER)) {
|
if ((UINT32)capsule.size() < sizeof(EFI_CAPSULE_HEADER)) {
|
||||||
@ -181,7 +184,7 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, UModelIndex & index)
|
|||||||
capsuleHeader->Flags);
|
capsuleHeader->Flags);
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
index = model->addItem(0, Types::Capsule, Subtypes::UefiCapsule, name, UString(), info, header, body, UByteArray(), Fixed);
|
index = model->addItem(model->offset(parent) + localOffset, Types::Capsule, Subtypes::UefiCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent);
|
||||||
}
|
}
|
||||||
// Check buffer for being Toshiba capsule header
|
// Check buffer for being Toshiba capsule header
|
||||||
else if (capsule.startsWith(TOSHIBA_CAPSULE_GUID)) {
|
else if (capsule.startsWith(TOSHIBA_CAPSULE_GUID)) {
|
||||||
@ -213,7 +216,7 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, UModelIndex & index)
|
|||||||
capsuleHeader->Flags);
|
capsuleHeader->Flags);
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
index = model->addItem(0, Types::Capsule, Subtypes::ToshibaCapsule, name, UString(), info, header, body, UByteArray(), Fixed);
|
index = model->addItem(model->offset(parent) + localOffset, Types::Capsule, Subtypes::ToshibaCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent);
|
||||||
}
|
}
|
||||||
// Check buffer for being extended Aptio capsule header
|
// Check buffer for being extended Aptio capsule header
|
||||||
else if (capsule.startsWith(APTIO_SIGNED_CAPSULE_GUID)
|
else if (capsule.startsWith(APTIO_SIGNED_CAPSULE_GUID)
|
||||||
@ -255,7 +258,7 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, UModelIndex & index)
|
|||||||
capsuleHeader->CapsuleHeader.Flags);
|
capsuleHeader->CapsuleHeader.Flags);
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
index = model->addItem(0, Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, UString(), info, header, body, UByteArray(), Fixed);
|
index = model->addItem(model->offset(parent) + localOffset, Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent);
|
||||||
|
|
||||||
// Show message about possible Aptio signature break
|
// Show message about possible Aptio signature break
|
||||||
if (signedCapsule) {
|
if (signedCapsule) {
|
||||||
@ -265,9 +268,6 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, UModelIndex & index)
|
|||||||
|
|
||||||
// Capsule present
|
// Capsule present
|
||||||
if (capsuleHeaderSize > 0) {
|
if (capsuleHeaderSize > 0) {
|
||||||
// Set imageBase for proper alignment calculation
|
|
||||||
imageBase = capsuleHeaderSize;
|
|
||||||
|
|
||||||
UByteArray image = capsule.mid(capsuleHeaderSize);
|
UByteArray image = capsule.mid(capsuleHeaderSize);
|
||||||
UModelIndex imageIndex;
|
UModelIndex imageIndex;
|
||||||
|
|
||||||
@ -574,6 +574,9 @@ USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 l
|
|||||||
// Add descriptor tree item
|
// Add descriptor tree item
|
||||||
UModelIndex regionIndex = model->addItem(model->offset(parent) + localOffset, Types::Region, Subtypes::DescriptorRegion, name, UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
|
UModelIndex regionIndex = model->addItem(model->offset(parent) + localOffset, Types::Region, Subtypes::DescriptorRegion, name, UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
|
||||||
|
|
||||||
|
// Set image base
|
||||||
|
imageBase = model->offset(parent) + localOffset;
|
||||||
|
|
||||||
// Parse regions
|
// Parse regions
|
||||||
USTATUS result = U_SUCCESS;
|
USTATUS result = U_SUCCESS;
|
||||||
USTATUS parseResult = U_SUCCESS;
|
USTATUS parseResult = U_SUCCESS;
|
||||||
@ -697,10 +700,10 @@ USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset
|
|||||||
if (versionFound) {
|
if (versionFound) {
|
||||||
const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset);
|
const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset);
|
||||||
info += usprintf("\nVersion: %u.%u.%u.%u",
|
info += usprintf("\nVersion: %u.%u.%u.%u",
|
||||||
version->major,
|
version->Major,
|
||||||
version->minor,
|
version->Minor,
|
||||||
version->bugfix,
|
version->Bugfix,
|
||||||
version->build);
|
version->Build);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,30 +783,32 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
|
|||||||
if (!index.isValid())
|
if (!index.isValid())
|
||||||
return U_INVALID_PARAMETER;
|
return U_INVALID_PARAMETER;
|
||||||
|
|
||||||
// Get parsing data
|
// Get item data
|
||||||
|
UByteArray data = model->body(index);
|
||||||
UINT32 headerSize = model->header(index).size();
|
UINT32 headerSize = model->header(index).size();
|
||||||
UINT32 offset = model->offset(index) + headerSize;
|
UINT32 offset = model->offset(index) + headerSize;
|
||||||
|
|
||||||
// Get item data
|
|
||||||
UByteArray data = model->body(index);
|
|
||||||
|
|
||||||
// Search for first volume
|
|
||||||
USTATUS result;
|
USTATUS result;
|
||||||
UINT32 prevVolumeOffset;
|
UString name;
|
||||||
|
UString info;
|
||||||
|
|
||||||
result = findNextVolume(index, data, offset, 0, prevVolumeOffset);
|
// Search for the first item
|
||||||
|
UINT8 prevItemType;
|
||||||
|
UINT32 prevItemOffset;
|
||||||
|
UINT32 prevItemSize;
|
||||||
|
UINT32 prevItemAltSize;
|
||||||
|
|
||||||
|
result = findNextRawAreaItem(index, 0, prevItemType, prevItemOffset, prevItemSize, prevItemAltSize);
|
||||||
if (result)
|
if (result)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (bgFirstVolumeOffset == 0x100000000ULL)
|
if (bgFirstVolumeOffset == 0x100000000ULL)
|
||||||
bgFirstVolumeOffset = model->offset(index) + prevVolumeOffset;
|
bgFirstVolumeOffset = model->offset(index) + prevItemOffset;
|
||||||
|
|
||||||
// First volume is not at the beginning of RAW area
|
// First item is not at the beginning of this raw area
|
||||||
UString name;
|
if (prevItemOffset > 0) {
|
||||||
UString info;
|
|
||||||
if (prevVolumeOffset > 0) {
|
|
||||||
// Get info
|
// Get info
|
||||||
UByteArray padding = data.left(prevVolumeOffset);
|
UByteArray padding = data.left(prevItemOffset);
|
||||||
name = UString("Padding");
|
name = UString("Padding");
|
||||||
info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size());
|
info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size());
|
||||||
|
|
||||||
@ -811,16 +816,17 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
|
|||||||
model->addItem(offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
model->addItem(offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Search for and parse all volumes
|
// Search for and parse all items
|
||||||
UINT32 volumeOffset = prevVolumeOffset;
|
UINT8 itemType = prevItemType;
|
||||||
UINT32 prevVolumeSize = 0;
|
UINT32 itemOffset = prevItemOffset;
|
||||||
|
UINT32 itemSize = prevItemSize;
|
||||||
|
UINT32 itemAltSize = prevItemAltSize;
|
||||||
|
|
||||||
while (!result)
|
while (!result) {
|
||||||
{
|
// Padding between items
|
||||||
// Padding between volumes
|
if (itemOffset > prevItemOffset + prevItemSize) {
|
||||||
if (volumeOffset > prevVolumeOffset + prevVolumeSize) {
|
UINT32 paddingOffset = prevItemOffset + prevItemSize;
|
||||||
UINT32 paddingOffset = prevVolumeOffset + prevVolumeSize;
|
UINT32 paddingSize = itemOffset - paddingOffset;
|
||||||
UINT32 paddingSize = volumeOffset - paddingOffset;
|
|
||||||
UByteArray padding = data.mid(paddingOffset, paddingSize);
|
UByteArray padding = data.mid(paddingOffset, paddingSize);
|
||||||
|
|
||||||
// Get info
|
// Get info
|
||||||
@ -831,65 +837,73 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
|
|||||||
model->addItem(offset + paddingOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
model->addItem(offset + paddingOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get volume size
|
// Check that item is fully present in input
|
||||||
UINT32 volumeSize = 0;
|
if (itemSize > (UINT32)data.size() || itemOffset + itemSize > (UINT32)data.size()) {
|
||||||
UINT32 bmVolumeSize = 0;
|
// Mark the rest as padding and finish parsing
|
||||||
result = getVolumeSize(data, volumeOffset, volumeSize, bmVolumeSize);
|
UByteArray padding = data.mid(itemOffset);
|
||||||
if (result) {
|
|
||||||
msg(usprintf("%s: getVolumeSize failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that volume is fully present in input
|
|
||||||
if (volumeSize > (UINT32)data.size() || volumeOffset + volumeSize > (UINT32)data.size()) {
|
|
||||||
// Mark the rest as padding and finish the parsing
|
|
||||||
UByteArray padding = data.mid(volumeOffset);
|
|
||||||
|
|
||||||
// Get info
|
// Get info
|
||||||
name = UString("Padding");
|
name = UString("Padding");
|
||||||
info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size());
|
info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size());
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
UModelIndex paddingIndex = model->addItem(offset + volumeOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
UModelIndex paddingIndex = model->addItem(offset + itemOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
||||||
msg(usprintf("%s: one of volumes inside overlaps the end of data", __FUNCTION__), paddingIndex);
|
msg(usprintf("%s: one of volumes inside overlaps the end of data", __FUNCTION__), paddingIndex);
|
||||||
|
|
||||||
// Update variables
|
// Update variables
|
||||||
prevVolumeOffset = volumeOffset;
|
prevItemOffset = itemOffset;
|
||||||
prevVolumeSize = padding.size();
|
prevItemSize = padding.size();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse current volume's header
|
// Parse current volume's header
|
||||||
|
if (itemType == Types::Volume) {
|
||||||
UModelIndex volumeIndex;
|
UModelIndex volumeIndex;
|
||||||
UByteArray volume = data.mid(volumeOffset, volumeSize);
|
UByteArray volume = data.mid(itemOffset, itemSize);
|
||||||
result = parseVolumeHeader(volume, headerSize + volumeOffset, index, volumeIndex);
|
result = parseVolumeHeader(volume, headerSize + itemOffset, index, volumeIndex);
|
||||||
if (result) {
|
if (result) {
|
||||||
msg(usprintf("%s: volume header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
|
msg(usprintf("%s: volume header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
|
||||||
} else {
|
} else {
|
||||||
// Show messages
|
// Show messages
|
||||||
if (volumeSize != bmVolumeSize)
|
if (itemSize != itemAltSize)
|
||||||
msg(usprintf("%s: volume size stored in header %Xh differs from calculated using block map %Xh", __FUNCTION__,
|
msg(usprintf("%s: volume size stored in header %Xh differs from calculated using block map %Xh", __FUNCTION__,
|
||||||
volumeSize, bmVolumeSize),
|
itemSize, itemAltSize),
|
||||||
volumeIndex);
|
volumeIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
// Go to next volume
|
else if (itemType == Types::Microcode) {
|
||||||
prevVolumeOffset = volumeOffset;
|
UModelIndex microcodeIndex;
|
||||||
prevVolumeSize = volumeSize;
|
UByteArray microcode = data.mid(itemOffset, itemSize);
|
||||||
result = findNextVolume(index, data, offset, volumeOffset + prevVolumeSize, volumeOffset);
|
result = parseIntelMicrocodeHeader(microcode, headerSize + itemOffset, index, microcodeIndex);
|
||||||
|
if (result) {
|
||||||
|
msg(usprintf("%s: microcode header parsing failed with error ", __FUNCTION__) + errorCodeToUString(result), index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return U_UNKNOWN_ITEM_TYPE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go to next item
|
||||||
|
prevItemOffset = itemOffset;
|
||||||
|
prevItemSize = itemSize;
|
||||||
|
prevItemType = itemType;
|
||||||
|
result = findNextRawAreaItem(index, itemOffset + prevItemSize, itemType, itemOffset, itemSize, itemAltSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fixes clang analyzer warning
|
||||||
|
(void)prevItemType;
|
||||||
|
|
||||||
// Padding at the end of RAW area
|
// Padding at the end of RAW area
|
||||||
volumeOffset = prevVolumeOffset + prevVolumeSize;
|
itemOffset = prevItemOffset + prevItemSize;
|
||||||
if ((UINT32)data.size() > volumeOffset) {
|
if ((UINT32)data.size() > itemOffset) {
|
||||||
UByteArray padding = data.mid(volumeOffset);
|
UByteArray padding = data.mid(itemOffset);
|
||||||
|
|
||||||
// Get info
|
// Get info
|
||||||
name = UString("Padding");
|
name = UString("Padding");
|
||||||
info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size());
|
info = usprintf("Full size: %Xh (%u)", padding.size(), padding.size());
|
||||||
|
|
||||||
// Add tree item
|
// Add tree item
|
||||||
model->addItem(offset + volumeOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
model->addItem(offset + itemOffset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse bodies
|
// Parse bodies
|
||||||
@ -899,6 +913,9 @@ USTATUS FfsParser::parseRawArea(const UModelIndex & index)
|
|||||||
case Types::Volume:
|
case Types::Volume:
|
||||||
parseVolumeBody(current);
|
parseVolumeBody(current);
|
||||||
break;
|
break;
|
||||||
|
case Types::Microcode:
|
||||||
|
// Parsing already done
|
||||||
|
break;
|
||||||
case Types::Padding:
|
case Types::Padding:
|
||||||
// No parsing required
|
// No parsing required
|
||||||
break;
|
break;
|
||||||
@ -947,8 +964,9 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
|
|||||||
headerSize = volumeHeader->ExtHeaderOffset + extendedHeader->ExtHeaderSize;
|
headerSize = volumeHeader->ExtHeaderOffset + extendedHeader->ExtHeaderSize;
|
||||||
extendedHeaderGuid = extendedHeader->FvName;
|
extendedHeaderGuid = extendedHeader->FvName;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
headerSize = volumeHeader->HeaderLength;
|
headerSize = volumeHeader->HeaderLength;
|
||||||
|
}
|
||||||
|
|
||||||
// Extended header end can be unaligned
|
// Extended header end can be unaligned
|
||||||
headerSize = ALIGN8(headerSize);
|
headerSize = ALIGN8(headerSize);
|
||||||
@ -956,6 +974,7 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
|
|||||||
// Check for volume structure to be known
|
// Check for volume structure to be known
|
||||||
bool isUnknown = true;
|
bool isUnknown = true;
|
||||||
bool isNvramVolume = false;
|
bool isNvramVolume = false;
|
||||||
|
bool isMicrocodeVolume = false;
|
||||||
UINT8 ffsVersion = 0;
|
UINT8 ffsVersion = 0;
|
||||||
|
|
||||||
// Check for FFS v2 volume
|
// Check for FFS v2 volume
|
||||||
@ -977,6 +996,13 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
|
|||||||
isNvramVolume = true;
|
isNvramVolume = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for Microcode volume
|
||||||
|
if (guid == EFI_APPLE_MICROCODE_VOLUME_GUID) {
|
||||||
|
isUnknown = false;
|
||||||
|
isMicrocodeVolume = true;
|
||||||
|
headerSize = EFI_APPLE_MICROCODE_VOLUME_HEADER_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
// Check volume revision and alignment
|
// Check volume revision and alignment
|
||||||
bool msgAlignmentBitsSet = false;
|
bool msgAlignmentBitsSet = false;
|
||||||
bool msgUnaligned = false;
|
bool msgUnaligned = false;
|
||||||
@ -1071,6 +1097,8 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
|
|||||||
subtype = Subtypes::Ffs3Volume;
|
subtype = Subtypes::Ffs3Volume;
|
||||||
else if (isNvramVolume)
|
else if (isNvramVolume)
|
||||||
subtype = Subtypes::NvramVolume;
|
subtype = Subtypes::NvramVolume;
|
||||||
|
else if (isMicrocodeVolume)
|
||||||
|
subtype = Subtypes::MicrocodeVolume;
|
||||||
}
|
}
|
||||||
index = model->addItem(model->offset(parent) + localOffset, Types::Volume, subtype, name, text, info, header, body, UByteArray(), Fixed, parent, mode);
|
index = model->addItem(model->offset(parent) + localOffset, Types::Volume, subtype, name, text, info, header, body, UByteArray(), Fixed, parent, mode);
|
||||||
|
|
||||||
@ -1103,67 +1131,82 @@ USTATUS FfsParser::parseVolumeHeader(const UByteArray & volume, const UINT32 loc
|
|||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::findNextVolume(const UModelIndex & index, const UByteArray & bios, const UINT32 globalOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset)
|
USTATUS FfsParser::findNextRawAreaItem(const UModelIndex & index, const UINT32 localOffset, UINT8 & nextItemType, UINT32 & nextItemOffset, UINT32 & nextItemSize, UINT32 & nextItemAlternativeSize)
|
||||||
{
|
{
|
||||||
int nextIndex = bios.indexOf(EFI_FV_SIGNATURE, volumeOffset);
|
UByteArray data = model->body(index);
|
||||||
if (nextIndex < EFI_FV_SIGNATURE_OFFSET)
|
UINT32 dataSize = data.size();
|
||||||
return U_VOLUMES_NOT_FOUND;
|
|
||||||
|
|
||||||
// Check volume header to be sane
|
if (dataSize < sizeof(UINT32))
|
||||||
for (; nextIndex > 0; nextIndex = bios.indexOf(EFI_FV_SIGNATURE, nextIndex + 1)) {
|
return U_STORES_NOT_FOUND;
|
||||||
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + nextIndex - EFI_FV_SIGNATURE_OFFSET);
|
|
||||||
|
UINT32 offset = localOffset;
|
||||||
|
for (; offset < dataSize - sizeof(UINT32); offset++) {
|
||||||
|
const UINT32* currentPos = (const UINT32*)(data.constData() + offset);
|
||||||
|
const UINT32 restSize = dataSize - offset;
|
||||||
|
UINT32 magic;
|
||||||
|
memcpy(&magic, currentPos, sizeof(UINT32));
|
||||||
|
if (magic == INTEL_MICROCODE_HEADER_VERSION) {// 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) {
|
||||||
|
reservedBytesValid = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!reservedBytesValid)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// All checks passed, microcode found
|
||||||
|
nextItemType = Types::Microcode;
|
||||||
|
nextItemSize = ucodeHeader->TotalSize;
|
||||||
|
nextItemAlternativeSize = ucodeHeader->TotalSize;
|
||||||
|
nextItemOffset = offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (magic == EFI_FV_SIGNATURE) {
|
||||||
|
if (offset < EFI_FV_SIGNATURE_OFFSET)
|
||||||
|
continue;
|
||||||
|
offset -= EFI_FV_SIGNATURE_OFFSET;
|
||||||
|
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(data.constData() + offset);
|
||||||
if (volumeHeader->FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY) || volumeHeader->FvLength >= 0xFFFFFFFFUL) {
|
if (volumeHeader->FvLength < sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY) || volumeHeader->FvLength >= 0xFFFFFFFFUL) {
|
||||||
msg(usprintf("%s: volume candidate at offset %Xh skipped, has invalid FvLength %" PRIX64 "h", __FUNCTION__,
|
|
||||||
globalOffset + (nextIndex - EFI_FV_SIGNATURE_OFFSET),
|
|
||||||
volumeHeader->FvLength), index);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (volumeHeader->Revision != 1 && volumeHeader->Revision != 2) {
|
if (volumeHeader->Revision != 1 && volumeHeader->Revision != 2) {
|
||||||
msg(usprintf("%s: volume candidate at offset %Xh skipped, has invalid Revision byte value %02Xh", __FUNCTION__,
|
|
||||||
globalOffset + (nextIndex - EFI_FV_SIGNATURE_OFFSET),
|
|
||||||
volumeHeader->Revision), index);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// All checks passed, volume found
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// No more volumes found
|
|
||||||
if (nextIndex < EFI_FV_SIGNATURE_OFFSET)
|
|
||||||
return U_VOLUMES_NOT_FOUND;
|
|
||||||
|
|
||||||
nextVolumeOffset = nextIndex - EFI_FV_SIGNATURE_OFFSET;
|
// Calculate alternative volume size using it's BlockMap
|
||||||
return U_SUCCESS;
|
nextItemAlternativeSize = 0;
|
||||||
}
|
const EFI_FV_BLOCK_MAP_ENTRY* entry = (const EFI_FV_BLOCK_MAP_ENTRY*)(data.constData() + offset + sizeof(EFI_FIRMWARE_VOLUME_HEADER));
|
||||||
|
|
||||||
USTATUS FfsParser::getVolumeSize(const UByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize)
|
|
||||||
{
|
|
||||||
// Check that there is space for the volume header and at least two block map entries.
|
|
||||||
if ((UINT32)bios.size() < volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER) + 2 * sizeof(EFI_FV_BLOCK_MAP_ENTRY))
|
|
||||||
return U_INVALID_VOLUME;
|
|
||||||
|
|
||||||
// Populate volume header
|
|
||||||
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)(bios.constData() + volumeOffset);
|
|
||||||
|
|
||||||
// Check volume signature
|
|
||||||
if (UByteArray((const char*)&volumeHeader->Signature, sizeof(volumeHeader->Signature)) != EFI_FV_SIGNATURE)
|
|
||||||
return U_INVALID_VOLUME;
|
|
||||||
|
|
||||||
// Calculate volume size using BlockMap
|
|
||||||
const EFI_FV_BLOCK_MAP_ENTRY* entry = (const EFI_FV_BLOCK_MAP_ENTRY*)(bios.constData() + volumeOffset + sizeof(EFI_FIRMWARE_VOLUME_HEADER));
|
|
||||||
UINT32 calcVolumeSize = 0;
|
|
||||||
while (entry->NumBlocks != 0 && entry->Length != 0) {
|
while (entry->NumBlocks != 0 && entry->Length != 0) {
|
||||||
if ((void*)entry > bios.constData() + bios.size())
|
if ((void*)entry >= data.constData() + data.size()) {
|
||||||
return U_INVALID_VOLUME;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
calcVolumeSize += entry->NumBlocks * entry->Length;
|
nextItemAlternativeSize += entry->NumBlocks * entry->Length;
|
||||||
entry += 1;
|
entry += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
volumeSize = (UINT32)volumeHeader->FvLength;
|
// All checks passed, volume found
|
||||||
bmVolumeSize = calcVolumeSize;
|
nextItemType = Types::Volume;
|
||||||
|
nextItemSize = volumeHeader->FvLength;
|
||||||
|
nextItemOffset = offset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (volumeSize == 0)
|
// No more stores found
|
||||||
return U_INVALID_VOLUME;
|
if (offset >= dataSize - sizeof(UINT32))
|
||||||
|
return U_STORES_NOT_FOUND;
|
||||||
|
|
||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
@ -1199,6 +1242,10 @@ USTATUS FfsParser::parseVolumeBody(const UModelIndex & index)
|
|||||||
if (model->subtype(index) == Subtypes::NvramVolume)
|
if (model->subtype(index) == Subtypes::NvramVolume)
|
||||||
return nvramParser->parseNvramVolumeBody(index);
|
return nvramParser->parseNvramVolumeBody(index);
|
||||||
|
|
||||||
|
// Parse Microcode volume with a dedicated function
|
||||||
|
if (model->subtype(index) == Subtypes::MicrocodeVolume)
|
||||||
|
return parseMicrocodeVolumeBody(index);
|
||||||
|
|
||||||
// Get required values from parsing data
|
// Get required values from parsing data
|
||||||
UINT8 emptyByte = 0xFF;
|
UINT8 emptyByte = 0xFF;
|
||||||
UINT8 ffsVersion = 2;
|
UINT8 ffsVersion = 2;
|
||||||
@ -1732,7 +1779,8 @@ USTATUS FfsParser::parsePadFileBody(const UModelIndex & index)
|
|||||||
// Rename the file
|
// Rename the file
|
||||||
model->setName(index, UString("Non-empty pad-file"));
|
model->setName(index, UString("Non-empty pad-file"));
|
||||||
|
|
||||||
return U_SUCCESS;
|
// Parse contents as RAW area
|
||||||
|
return parseRawArea(dataIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex & index, const bool insertIntoTree)
|
USTATUS FfsParser::parseSections(const UByteArray & sections, const UModelIndex & index, const bool insertIntoTree)
|
||||||
@ -3484,7 +3532,7 @@ USTATUS FfsParser::parseFit(const UModelIndex & index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (currentEntry->Type == FIT_TYPE_TXT_CONF_POLICY)
|
if (currentEntry->Type == FIT_TYPE_TXT_CONF_POLICY)
|
||||||
parseTxtConfigurationPolicy(currentEntry, info);
|
parseFitEntryTxtConfigurationPolicy(currentEntry, info);
|
||||||
|
|
||||||
// Set item index
|
// Set item index
|
||||||
if (currentEntry->Address > addressDiff && currentEntry->Address < 0xFFFFFFFFUL) { // Only elements in the image need to be parsed
|
if (currentEntry->Address > addressDiff && currentEntry->Address < 0xFFFFFFFFUL) { // Only elements in the image need to be parsed
|
||||||
@ -3497,21 +3545,21 @@ USTATUS FfsParser::parseFit(const UModelIndex & index)
|
|||||||
|
|
||||||
switch (currentEntry->Type) {
|
switch (currentEntry->Type) {
|
||||||
case FIT_TYPE_MICROCODE:
|
case FIT_TYPE_MICROCODE:
|
||||||
status = parseIntelMicrocode(item, localOffset, itemIndex, info, currentEntrySize);
|
status = parseFitEntryMicrocode(item, localOffset, itemIndex, info, currentEntrySize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FIT_TYPE_BIOS_AC_MODULE:
|
case FIT_TYPE_BIOS_AC_MODULE:
|
||||||
status = parseIntelAcm(item, localOffset, itemIndex, info, currentEntrySize);
|
status = parseFitEntryAcm(item, localOffset, itemIndex, info, currentEntrySize);
|
||||||
acmIndex = itemIndex;
|
acmIndex = itemIndex;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FIT_TYPE_AC_KEY_MANIFEST:
|
case FIT_TYPE_AC_KEY_MANIFEST:
|
||||||
status = parseIntelBootGuardKeyManifest(item, localOffset, itemIndex, info, currentEntrySize);
|
status = parseFitEntryBootGuardKeyManifest(item, localOffset, itemIndex, info, currentEntrySize);
|
||||||
kmIndex = itemIndex;
|
kmIndex = itemIndex;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FIT_TYPE_AC_BOOT_POLICY:
|
case FIT_TYPE_AC_BOOT_POLICY:
|
||||||
status = parseIntelBootGuardBootPolicy(item, localOffset, itemIndex, info, currentEntrySize);
|
status = parseFitEntryBootGuardBootPolicy(item, localOffset, itemIndex, info, currentEntrySize);
|
||||||
bpIndex = itemIndex;
|
bpIndex = itemIndex;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -3596,7 +3644,7 @@ USTATUS FfsParser::findFitRecursive(const UModelIndex & index, UModelIndex & fou
|
|||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::parseIntelMicrocode(const UByteArray & microcode, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
|
USTATUS FfsParser::parseFitEntryMicrocode(const UByteArray & microcode, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
|
||||||
{
|
{
|
||||||
U_UNUSED_PARAMETER(parent);
|
U_UNUSED_PARAMETER(parent);
|
||||||
if ((UINT32)microcode.size() < localOffset + sizeof(INTEL_MICROCODE_HEADER)) {
|
if ((UINT32)microcode.size() < localOffset + sizeof(INTEL_MICROCODE_HEADER)) {
|
||||||
@ -3633,33 +3681,10 @@ USTATUS FfsParser::parseIntelMicrocode(const UByteArray & microcode, const UINT3
|
|||||||
header->DateYear
|
header->DateYear
|
||||||
);
|
);
|
||||||
realSize = mcSize;
|
realSize = mcSize;
|
||||||
|
|
||||||
// Add Microcode header info
|
|
||||||
microcodeInfo += usprintf(
|
|
||||||
"Microcode Update Capsule found at offset %Xh\n"
|
|
||||||
"Checksum: %08Xh CPU Flags: %08Xh CPU Signature: %08Xh\n"
|
|
||||||
"Data Size: %08Xh Date: %02X.%02X.%04X Loader Revision: %08Xh\n"
|
|
||||||
"Date: %02X.%02X.%04X ModuleSize: %08Xh EntryPoint: %08Xh\n"
|
|
||||||
"Reserved: %02Xh Revision: %08Xh TotalSize: %08Xh\n"
|
|
||||||
"Version: %08Xh"
|
|
||||||
"\n------------------------------------------------------------------------\n\n",
|
|
||||||
model->offset(parent) + localOffset,
|
|
||||||
header->Checksum,
|
|
||||||
header->CpuFlags,
|
|
||||||
header->CpuSignature,
|
|
||||||
header->DataSize,
|
|
||||||
header->DateDay, header->DateMonth, header->DateYear,
|
|
||||||
header->LoaderRevision,
|
|
||||||
header->Reserved,
|
|
||||||
header->Revision,
|
|
||||||
header->TotalSize,
|
|
||||||
header->Version
|
|
||||||
);
|
|
||||||
|
|
||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::parseTxtConfigurationPolicy(const FIT_ENTRY* entry, UString & info)
|
USTATUS FfsParser::parseFitEntryTxtConfigurationPolicy(const FIT_ENTRY* entry, UString & info)
|
||||||
{
|
{
|
||||||
U_UNUSED_PARAMETER(info);
|
U_UNUSED_PARAMETER(info);
|
||||||
const TXT_CONFIG_POLICY* txtCfg = (const TXT_CONFIG_POLICY*)entry;
|
const TXT_CONFIG_POLICY* txtCfg = (const TXT_CONFIG_POLICY*)entry;
|
||||||
@ -3694,7 +3719,7 @@ USTATUS FfsParser::parseTxtConfigurationPolicy(const FIT_ENTRY* entry, UString &
|
|||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::parseIntelAcm(const UByteArray & acm, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
|
USTATUS FfsParser::parseFitEntryAcm(const UByteArray & acm, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
|
||||||
{
|
{
|
||||||
if ((UINT32)acm.size() < localOffset + sizeof(INTEL_ACM_HEADER)) {
|
if ((UINT32)acm.size() < localOffset + sizeof(INTEL_ACM_HEADER)) {
|
||||||
return U_INVALID_ACM;
|
return U_INVALID_ACM;
|
||||||
@ -3778,7 +3803,7 @@ USTATUS FfsParser::parseIntelAcm(const UByteArray & acm, const UINT32 localOffse
|
|||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::parseIntelBootGuardKeyManifest(const UByteArray & keyManifest, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
|
USTATUS FfsParser::parseFitEntryBootGuardKeyManifest(const UByteArray & keyManifest, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
|
||||||
{
|
{
|
||||||
U_UNUSED_PARAMETER(realSize);
|
U_UNUSED_PARAMETER(realSize);
|
||||||
if ((UINT32)keyManifest.size() < localOffset + sizeof(BG_KEY_MANIFEST)) {
|
if ((UINT32)keyManifest.size() < localOffset + sizeof(BG_KEY_MANIFEST)) {
|
||||||
@ -3844,7 +3869,7 @@ USTATUS FfsParser::parseIntelBootGuardKeyManifest(const UByteArray & keyManifest
|
|||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::findNextElement(const UByteArray & bootPolicy, const UINT32 elementOffset, UINT32 & nextElementOffset, UINT32 & nextElementSize)
|
USTATUS FfsParser::findNextBootGuardBootPolicyElement(const UByteArray & bootPolicy, const UINT32 elementOffset, UINT32 & nextElementOffset, UINT32 & nextElementSize)
|
||||||
{
|
{
|
||||||
UINT32 dataSize = bootPolicy.size();
|
UINT32 dataSize = bootPolicy.size();
|
||||||
if (dataSize < sizeof(UINT64)) {
|
if (dataSize < sizeof(UINT64)) {
|
||||||
@ -3882,7 +3907,7 @@ USTATUS FfsParser::findNextElement(const UByteArray & bootPolicy, const UINT32 e
|
|||||||
return U_ELEMENTS_NOT_FOUND;
|
return U_ELEMENTS_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS FfsParser::parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
|
USTATUS FfsParser::parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolicy, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize)
|
||||||
{
|
{
|
||||||
U_UNUSED_PARAMETER(realSize);
|
U_UNUSED_PARAMETER(realSize);
|
||||||
if ((UINT32)bootPolicy.size() < localOffset + sizeof(BG_BOOT_POLICY_MANIFEST_HEADER)) {
|
if ((UINT32)bootPolicy.size() < localOffset + sizeof(BG_BOOT_POLICY_MANIFEST_HEADER)) {
|
||||||
@ -3923,7 +3948,7 @@ USTATUS FfsParser::parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy,
|
|||||||
// Iterate over elements to get them all
|
// Iterate over elements to get them all
|
||||||
UINT32 elementOffset = 0;
|
UINT32 elementOffset = 0;
|
||||||
UINT32 elementSize = 0;
|
UINT32 elementSize = 0;
|
||||||
USTATUS status = findNextElement(bootPolicy, localOffset + sizeof(BG_BOOT_POLICY_MANIFEST_HEADER), elementOffset, elementSize);
|
USTATUS status = findNextBootGuardBootPolicyElement(bootPolicy, localOffset + sizeof(BG_BOOT_POLICY_MANIFEST_HEADER), elementOffset, elementSize);
|
||||||
while (status == U_SUCCESS) {
|
while (status == U_SUCCESS) {
|
||||||
const UINT64* currentPos = (const UINT64*)(bootPolicy.constData() + elementOffset);
|
const UINT64* currentPos = (const UINT64*)(bootPolicy.constData() + elementOffset);
|
||||||
if (*currentPos == BG_BOOT_POLICY_MANIFEST_IBB_ELEMENT_TAG) {
|
if (*currentPos == BG_BOOT_POLICY_MANIFEST_IBB_ELEMENT_TAG) {
|
||||||
@ -4062,13 +4087,119 @@ USTATUS FfsParser::parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy,
|
|||||||
bootGuardInfo += usprintf("%02X", elementHeader->KeySignature.Signature.Signature[i]);
|
bootGuardInfo += usprintf("%02X", elementHeader->KeySignature.Signature.Signature[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status = findNextElement(bootPolicy, elementOffset + elementSize, elementOffset, elementSize);
|
status = findNextBootGuardBootPolicyElement(bootPolicy, elementOffset + elementSize, elementOffset, elementSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
bootGuardInfo += UString("\n------------------------------------------------------------------------\n\n");
|
bootGuardInfo += UString("\n------------------------------------------------------------------------\n\n");
|
||||||
bgBootPolicyFound = true;
|
bgBootPolicyFound = true;
|
||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
USTATUS FfsParser::parseMicrocodeVolumeBody(const UModelIndex & index)
|
||||||
|
{
|
||||||
|
const UINT32 headerSize = (UINT32)model->header(index).size();
|
||||||
|
const UINT32 bodySize = (UINT32)model->body(index).size();
|
||||||
|
UINT32 offset = 0;
|
||||||
|
USTATUS result = U_SUCCESS;
|
||||||
|
|
||||||
|
while(true) {
|
||||||
|
// Parse current microcode
|
||||||
|
UModelIndex currentMicrocode;
|
||||||
|
UByteArray ucode = model->body(index).mid(offset);
|
||||||
|
|
||||||
|
// Check for empty area
|
||||||
|
if (ucode.size() == ucode.count('\xFF') || ucode.size() == ucode.count('\x00')) {
|
||||||
|
result = U_INVALID_MICROCODE;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = parseIntelMicrocodeHeader(ucode, headerSize + offset, index, currentMicrocode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the rest as padding
|
||||||
|
if (result) {
|
||||||
|
if (offset < bodySize) {
|
||||||
|
// Get info
|
||||||
|
UString name = UString("Padding");
|
||||||
|
UString info = usprintf("Full size: %Xh (%u)", ucode.size(), ucode.size());
|
||||||
|
|
||||||
|
// Add tree item
|
||||||
|
model->addItem(model->offset(index) + headerSize + offset, Types::Padding, getPaddingType(ucode), name, UString(), info, UByteArray(), ucode, UByteArray(), Fixed, index);
|
||||||
|
}
|
||||||
|
return U_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get to next candidate
|
||||||
|
offset += model->header(currentMicrocode).size() + model->body(currentMicrocode).size() + model->tail(currentMicrocode).size();
|
||||||
|
if (offset >= bodySize)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return U_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
USTATUS FfsParser::parseIntelMicrocodeHeader(const UByteArray & microcode, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, UINT8 mode)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
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);
|
||||||
|
return U_INVALID_MICROCODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool reservedBytesValid = true;
|
||||||
|
for (UINT8 i = 0; i < sizeof(ucodeHeader->Reserved); i++)
|
||||||
|
if (ucodeHeader->Reserved[i] != INTEL_MICROCODE_HEADER_RESERVED_BYTE) {
|
||||||
|
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);
|
||||||
|
return U_INVALID_MICROCODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid microcode found
|
||||||
|
// Construct header and body
|
||||||
|
UByteArray header = microcode.left(sizeof(INTEL_MICROCODE_HEADER));
|
||||||
|
UByteArray body = microcode.mid(sizeof(INTEL_MICROCODE_HEADER), ucodeHeader->DataSize);
|
||||||
|
|
||||||
|
//TODO: recalculate microcode checksum
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Add tree item
|
||||||
|
index = model->addItem(model->offset(parent) + localOffset, Types::Microcode, Subtypes::IntelMicrocode, name, UString(), info, header, body, UByteArray(), Fixed, parent, mode);
|
||||||
|
|
||||||
|
// No need to parse body further for now
|
||||||
|
|
||||||
|
return U_SUCCESS;
|
||||||
|
}
|
||||||
|
@ -64,9 +64,6 @@ public:
|
|||||||
// Obtain TXT ACM Info
|
// Obtain TXT ACM Info
|
||||||
UString getTxtInfo() const { return txtInfo; }
|
UString getTxtInfo() const { return txtInfo; }
|
||||||
|
|
||||||
// Obtain Microcode Info
|
|
||||||
UString getMicrocodeInfo() const { return microcodeInfo; }
|
|
||||||
|
|
||||||
// Obtain offset/address difference
|
// Obtain offset/address difference
|
||||||
UINT64 getAddressDiff() { return addressDiff; }
|
UINT64 getAddressDiff() { return addressDiff; }
|
||||||
|
|
||||||
@ -102,18 +99,18 @@ private:
|
|||||||
UModelIndex bgDxeCoreIndex;
|
UModelIndex bgDxeCoreIndex;
|
||||||
|
|
||||||
UString txtInfo;
|
UString txtInfo;
|
||||||
UString microcodeInfo;
|
|
||||||
|
|
||||||
// First pass
|
// First pass
|
||||||
USTATUS performFirstPass(const UByteArray & imageFile, UModelIndex & index);
|
USTATUS performFirstPass(const UByteArray & imageFile, UModelIndex & index);
|
||||||
|
|
||||||
USTATUS parseCapsule(const UByteArray & capsule, UModelIndex & index);
|
USTATUS parseCapsule(const UByteArray & capsule, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||||
USTATUS parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
USTATUS parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||||
USTATUS parseGenericImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
USTATUS parseGenericImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||||
|
|
||||||
USTATUS parseRawArea(const UModelIndex & index);
|
USTATUS parseRawArea(const UModelIndex & index);
|
||||||
USTATUS parseVolumeHeader(const UByteArray & volume, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
USTATUS parseVolumeHeader(const UByteArray & volume, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
||||||
USTATUS parseVolumeBody(const UModelIndex & index);
|
USTATUS parseVolumeBody(const UModelIndex & index);
|
||||||
|
USTATUS parseMicrocodeVolumeBody(const UModelIndex & index);
|
||||||
USTATUS parseFileHeader(const UByteArray & file, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
USTATUS parseFileHeader(const UByteArray & file, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
||||||
USTATUS parseFileBody(const UModelIndex & index);
|
USTATUS parseFileBody(const UModelIndex & index);
|
||||||
USTATUS parseSectionHeader(const UByteArray & section, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const bool insertIntoTree, const UINT8 mode = CREATE_MODE_APPEND);
|
USTATUS parseSectionHeader(const UByteArray & section, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const bool insertIntoTree, const UINT8 mode = CREATE_MODE_APPEND);
|
||||||
@ -146,8 +143,8 @@ private:
|
|||||||
USTATUS parseTeImageSectionBody(const UModelIndex & index);
|
USTATUS parseTeImageSectionBody(const UModelIndex & index);
|
||||||
|
|
||||||
USTATUS parseAprioriRawSection(const UByteArray & body, UString & parsed);
|
USTATUS parseAprioriRawSection(const UByteArray & body, UString & parsed);
|
||||||
USTATUS findNextVolume(const UModelIndex & index, const UByteArray & bios, const UINT32 globalOffset, const UINT32 volumeOffset, UINT32 & nextVolumeOffset);
|
USTATUS findNextRawAreaItem(const UModelIndex & index, const UINT32 localOffset,
|
||||||
USTATUS getVolumeSize(const UByteArray & bios, const UINT32 volumeOffset, UINT32 & volumeSize, UINT32 & bmVolumeSize);
|
UINT8 & nextItemType, UINT32 & nextItemOffset, UINT32 & nextItemSize, UINT32 & nextItemAlternativeSize);
|
||||||
UINT32 getFileSize(const UByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion);
|
UINT32 getFileSize(const UByteArray & volume, const UINT32 fileOffset, const UINT8 ffsVersion);
|
||||||
UINT32 getSectionSize(const UByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion);
|
UINT32 getSectionSize(const UByteArray & file, const UINT32 sectionOffset, const UINT8 ffsVersion);
|
||||||
|
|
||||||
@ -161,17 +158,18 @@ private:
|
|||||||
|
|
||||||
USTATUS parseFit(const UModelIndex & index);
|
USTATUS parseFit(const UModelIndex & index);
|
||||||
USTATUS parseVendorHashFile(const UByteArray & fileGuid, const UModelIndex & index);
|
USTATUS parseVendorHashFile(const UByteArray & fileGuid, const UModelIndex & index);
|
||||||
|
USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, UINT8 mode = CREATE_MODE_APPEND);
|
||||||
|
|
||||||
#ifdef U_ENABLE_FIT_PARSING_SUPPORT
|
#ifdef U_ENABLE_FIT_PARSING_SUPPORT
|
||||||
USTATUS findFitRecursive(const UModelIndex & index, UModelIndex & found, UINT32 & fitOffset);
|
USTATUS findFitRecursive(const UModelIndex & index, UModelIndex & found, UINT32 & fitOffset);
|
||||||
|
|
||||||
// FIT entries
|
// FIT entries
|
||||||
USTATUS parseIntelMicrocode(const UByteArray & microcode, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
|
USTATUS parseFitEntryMicrocode(const UByteArray & microcode, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
|
||||||
USTATUS parseIntelAcm(const UByteArray & acm, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
|
USTATUS parseFitEntryAcm(const UByteArray & acm, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
|
||||||
USTATUS parseIntelBootGuardKeyManifest(const UByteArray & keyManifest, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
|
USTATUS parseFitEntryBootGuardKeyManifest(const UByteArray & keyManifest, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
|
||||||
USTATUS parseIntelBootGuardBootPolicy(const UByteArray & bootPolicy, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
|
USTATUS parseFitEntryBootGuardBootPolicy(const UByteArray & bootPolicy, const UINT32 localOffset, const UModelIndex & parent, UString & info, UINT32 &realSize);
|
||||||
USTATUS parseTxtConfigurationPolicy(const FIT_ENTRY* entry, UString & info);
|
USTATUS parseFitEntryTxtConfigurationPolicy(const FIT_ENTRY* entry, UString & info);
|
||||||
USTATUS findNextElement(const UByteArray & bootPolicy, const UINT32 elementOffset, UINT32 & nextElementOffset, UINT32 & nextElementSize);
|
USTATUS findNextBootGuardBootPolicyElement(const UByteArray & bootPolicy, const UINT32 elementOffset, UINT32 & nextElementOffset, UINT32 & nextElementSize);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
|
#ifdef U_ENABLE_NVRAM_PARSING_SUPPORT
|
||||||
|
@ -18,8 +18,8 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <cstdio>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <cstdio>
|
||||||
|
|
||||||
struct OperatorLessForGuids : public std::binary_function<EFI_GUID, EFI_GUID, bool>
|
struct OperatorLessForGuids : public std::binary_function<EFI_GUID, EFI_GUID, bool>
|
||||||
{
|
{
|
||||||
|
12
common/me.h
12
common/me.h
@ -22,12 +22,12 @@ const UByteArray ME_VERSION_SIGNATURE("\x24\x4D\x41\x4E", 4); //$MAN
|
|||||||
const UByteArray ME_VERSION_SIGNATURE2("\x24\x4D\x4E\x32", 4); //$MN2
|
const UByteArray ME_VERSION_SIGNATURE2("\x24\x4D\x4E\x32", 4); //$MN2
|
||||||
|
|
||||||
typedef struct ME_VERSION_ {
|
typedef struct ME_VERSION_ {
|
||||||
UINT32 signature;
|
UINT32 Signature;
|
||||||
UINT32 reserved;
|
UINT32 Reserved;
|
||||||
UINT16 major;
|
UINT16 Major;
|
||||||
UINT16 minor;
|
UINT16 Minor;
|
||||||
UINT16 bugfix;
|
UINT16 Bugfix;
|
||||||
UINT16 build;
|
UINT16 Build;
|
||||||
} ME_VERSION;
|
} ME_VERSION;
|
||||||
|
|
||||||
// Restore previous packing rules
|
// Restore previous packing rules
|
||||||
|
@ -108,6 +108,6 @@ UString flashMapGuidToUString(const EFI_GUID & guid)
|
|||||||
|| baGuid == NVRAM_PHOENIX_FLASH_MAP_EVSA6_GUID
|
|| baGuid == NVRAM_PHOENIX_FLASH_MAP_EVSA6_GUID
|
||||||
|| baGuid == NVRAM_PHOENIX_FLASH_MAP_EVSA7_GUID) return UString("EVSA store");
|
|| baGuid == NVRAM_PHOENIX_FLASH_MAP_EVSA7_GUID) return UString("EVSA store");
|
||||||
if (baGuid == NVRAM_PHOENIX_FLASH_MAP_SELF_GUID) return UString("Flash map");
|
if (baGuid == NVRAM_PHOENIX_FLASH_MAP_SELF_GUID) return UString("Flash map");
|
||||||
return UString();
|
return UString("Unknown");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1225,55 +1225,6 @@ USTATUS NvramParser::parseSlicMarkerHeader(const UByteArray & store, const UINT3
|
|||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
USTATUS NvramParser::parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode)
|
|
||||||
{
|
|
||||||
const UINT32 dataSize = (const UINT32)store.size();
|
|
||||||
|
|
||||||
// Check data size
|
|
||||||
if (dataSize < sizeof(INTEL_MICROCODE_HEADER)) {
|
|
||||||
msg(usprintf("%s: volume body is too small even for Intel microcode header", __FUNCTION__), parent);
|
|
||||||
return U_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get Intel microcode header
|
|
||||||
const INTEL_MICROCODE_HEADER* ucodeHeader = (const INTEL_MICROCODE_HEADER*)store.constData();
|
|
||||||
|
|
||||||
// Check store size
|
|
||||||
if (dataSize < ucodeHeader->TotalSize) {
|
|
||||||
msg(usprintf("%s: Intel microcode size %Xh (%u) is greater than volume body size %Xh (%u)", __FUNCTION__,
|
|
||||||
ucodeHeader->TotalSize, ucodeHeader->TotalSize,
|
|
||||||
dataSize, dataSize), parent);
|
|
||||||
return U_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct header and body
|
|
||||||
UByteArray header = store.left(sizeof(INTEL_MICROCODE_HEADER));
|
|
||||||
UByteArray body = store.mid(sizeof(INTEL_MICROCODE_HEADER), ucodeHeader->DataSize);
|
|
||||||
|
|
||||||
//TODO: recalculate microcode checksum
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
|
|
||||||
// Add tree item
|
|
||||||
index = model->addItem(localOffset, Types::Microcode, Subtypes::IntelMicrocode, name, UString(), info, header, body, UByteArray(), Fixed, parent, mode);
|
|
||||||
|
|
||||||
return U_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode)
|
USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode)
|
||||||
{
|
{
|
||||||
const UINT32 dataSize = (const UINT32)store.size();
|
const UINT32 dataSize = (const UINT32)store.size();
|
||||||
@ -1318,7 +1269,7 @@ USTATUS NvramParser::parseStoreHeader(const UByteArray & store, const UINT32 loc
|
|||||||
// Intel microcode
|
// Intel microcode
|
||||||
// Must be checked after SLIC marker because of the same *signature values
|
// Must be checked after SLIC marker because of the same *signature values
|
||||||
else if (*signature == INTEL_MICROCODE_HEADER_VERSION)
|
else if (*signature == INTEL_MICROCODE_HEADER_VERSION)
|
||||||
return parseIntelMicrocodeHeader(store, localOffset, parent, index, mode);
|
return ffsParser->parseIntelMicrocodeHeader(store, localOffset, parent, index, mode);
|
||||||
|
|
||||||
msg(usprintf("parseStoreHeader: don't know how to parse a header with signature %08Xh", *signature), parent);
|
msg(usprintf("parseStoreHeader: don't know how to parse a header with signature %08Xh", *signature), parent);
|
||||||
return U_SUCCESS;
|
return U_SUCCESS;
|
||||||
|
@ -62,7 +62,6 @@ private:
|
|||||||
USTATUS parseCmdbStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
USTATUS parseCmdbStoreHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
||||||
USTATUS parseSlicPubkeyHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
USTATUS parseSlicPubkeyHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
||||||
USTATUS parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
USTATUS parseSlicMarkerHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
||||||
USTATUS parseIntelMicrocodeHeader(const UByteArray & store, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const UINT8 mode = CREATE_MODE_APPEND);
|
|
||||||
|
|
||||||
USTATUS parseFdcStoreBody(const UModelIndex & index);
|
USTATUS parseFdcStoreBody(const UModelIndex & index);
|
||||||
USTATUS parseVssStoreBody(const UModelIndex & index, const UINT8 alignment);
|
USTATUS parseVssStoreBody(const UModelIndex & index, const UINT8 alignment);
|
||||||
|
@ -74,17 +74,6 @@ UString itemTypeToUString(const UINT8 type)
|
|||||||
UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
|
UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
|
||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Types::Root:
|
|
||||||
case Types::FreeSpace:
|
|
||||||
case Types::VssStore:
|
|
||||||
case Types::Vss2Store:
|
|
||||||
case Types::FdcStore:
|
|
||||||
case Types::FsysStore:
|
|
||||||
case Types::EvsaStore:
|
|
||||||
case Types::FtwStore:
|
|
||||||
case Types::FlashMapStore:
|
|
||||||
case Types::CmdbStore:
|
|
||||||
case Types::SlicData: return UString();
|
|
||||||
case Types::Image:
|
case Types::Image:
|
||||||
if (subtype == Subtypes::IntelImage) return UString("Intel");
|
if (subtype == Subtypes::IntelImage) return UString("Intel");
|
||||||
if (subtype == Subtypes::UefiImage) return UString("UEFI");
|
if (subtype == Subtypes::UefiImage) return UString("UEFI");
|
||||||
@ -99,6 +88,7 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
|
|||||||
if (subtype == Subtypes::Ffs2Volume) return UString("FFSv2");
|
if (subtype == Subtypes::Ffs2Volume) return UString("FFSv2");
|
||||||
if (subtype == Subtypes::Ffs3Volume) return UString("FFSv3");
|
if (subtype == Subtypes::Ffs3Volume) return UString("FFSv3");
|
||||||
if (subtype == Subtypes::NvramVolume) return UString("NVRAM");
|
if (subtype == Subtypes::NvramVolume) return UString("NVRAM");
|
||||||
|
if (subtype == Subtypes::MicrocodeVolume) return UString("Microcode");
|
||||||
break;
|
break;
|
||||||
case Types::Capsule:
|
case Types::Capsule:
|
||||||
if (subtype == Subtypes::AptioSignedCapsule) return UString("Aptio signed");
|
if (subtype == Subtypes::AptioSignedCapsule) return UString("Aptio signed");
|
||||||
@ -144,7 +134,7 @@ UString itemSubtypeToUString(const UINT8 type, const UINT8 subtype)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
return UString("Unknown");
|
return UString();
|
||||||
}
|
}
|
||||||
|
|
||||||
UString compressionTypeToUString(const UINT8 algorithm)
|
UString compressionTypeToUString(const UINT8 algorithm)
|
||||||
|
@ -78,7 +78,8 @@ namespace Subtypes {
|
|||||||
UnknownVolume = 110,
|
UnknownVolume = 110,
|
||||||
Ffs2Volume,
|
Ffs2Volume,
|
||||||
Ffs3Volume,
|
Ffs3Volume,
|
||||||
NvramVolume
|
NvramVolume,
|
||||||
|
MicrocodeVolume
|
||||||
};
|
};
|
||||||
|
|
||||||
enum RegionSubtypes {
|
enum RegionSubtypes {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
/* types.h
|
/* version.h
|
||||||
|
|
||||||
Copyright (c) 2015, Nikolaj Schlej. All rights reserved.
|
Copyright (c) 2018, LongSoft. All rights reserved.
|
||||||
This program and the accompanying materials
|
This program and the accompanying materials
|
||||||
are licensed and made available under the terms and conditions of the BSD License
|
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
|
which accompanies this distribution. The full text of the license may be found at
|
||||||
@ -14,6 +14,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||||||
#ifndef __VERSION_H__
|
#ifndef __VERSION_H__
|
||||||
#define __VERSION_H__
|
#define __VERSION_H__
|
||||||
|
|
||||||
#define PROGRAM_VERSION "NE alpha 51"
|
#define PROGRAM_VERSION "NE alpha 52"
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in New Issue
Block a user