mirror of
https://github.com/LongSoft/UEFITool.git
synced 2025-05-09 13:52:01 -04:00
common: Move Intel specific code to own file
Prepare for AMD specific parsers and move the Intel code into it's own file. Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com>
This commit is contained in:
parent
22bb757726
commit
3aefe281c4
11 changed files with 791 additions and 725 deletions
|
@ -19,6 +19,7 @@ SET(PROJECT_SOURCES
|
|||
../common/nvramparser.cpp
|
||||
../common/meparser.cpp
|
||||
../common/ffsparser.cpp
|
||||
../common/ffsparser_intel.cpp
|
||||
../common/fitparser.cpp
|
||||
../common/ffsreport.cpp
|
||||
../common/peimage.cpp
|
||||
|
|
|
@ -17,6 +17,7 @@ SET(PROJECT_SOURCES
|
|||
../common/nvram.cpp
|
||||
../common/nvramparser.cpp
|
||||
../common/ffsparser.cpp
|
||||
../common/ffsparser_intel.cpp
|
||||
../common/fitparser.cpp
|
||||
../common/peimage.cpp
|
||||
../common/treeitem.cpp
|
||||
|
|
|
@ -16,7 +16,7 @@ SET(PROJECT_FORMS
|
|||
gotoaddressdialog.ui
|
||||
)
|
||||
|
||||
SET(PROJECT_HEADERS
|
||||
SET(PROJECT_HEADERS
|
||||
uefitool.h
|
||||
hexspinbox.h
|
||||
searchdialog.h
|
||||
|
@ -25,7 +25,7 @@ SET(PROJECT_HEADERS
|
|||
gotoaddressdialog.h
|
||||
)
|
||||
|
||||
SET(PROJECT_SOURCES
|
||||
SET(PROJECT_SOURCES
|
||||
icons/uefitool.icns
|
||||
uefitool.rc
|
||||
uefitool_main.cpp
|
||||
|
@ -48,6 +48,7 @@ SET(PROJECT_SOURCES
|
|||
../common/utility.cpp
|
||||
../common/ffsbuilder.cpp
|
||||
../common/ffsparser.cpp
|
||||
../common/ffsparser_intel.cpp
|
||||
../common/ffsreport.cpp
|
||||
../common/treeitem.cpp
|
||||
../common/treemodel.cpp
|
||||
|
@ -101,7 +102,7 @@ SET(PROJECT_SOURCES
|
|||
../common/zlib/zutil.c
|
||||
)
|
||||
|
||||
QT_ADD_RESOURCES(PROJECT_SOURCES
|
||||
QT_ADD_RESOURCES(PROJECT_SOURCES
|
||||
uefitool.qrc
|
||||
)
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ HEADERS += uefitool.h \
|
|||
../common/meparser.h \
|
||||
../common/ffsops.h \
|
||||
../common/basetypes.h \
|
||||
../common/intel_descriptor.h \
|
||||
../common/descriptor.h \
|
||||
../common/gbe.h \
|
||||
../common/me.h \
|
||||
|
@ -108,6 +109,7 @@ SOURCES += uefitool_main.cpp \
|
|||
../common/utility.cpp \
|
||||
../common/ffsbuilder.cpp \
|
||||
../common/ffsparser.cpp \
|
||||
../common/ffsparser_intel.cpp \
|
||||
../common/ffsreport.cpp \
|
||||
../common/treeitem.cpp \
|
||||
../common/treemodel.cpp \
|
||||
|
|
|
@ -15,209 +15,6 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|||
|
||||
#include "basetypes.h"
|
||||
#include "ustring.h"
|
||||
#include "ubytearray.h"
|
||||
|
||||
// Make sure we use right packing rules
|
||||
#pragma pack(push,1)
|
||||
|
||||
// Flash descriptor header
|
||||
typedef struct FLASH_DESCRIPTOR_HEADER_ {
|
||||
UINT8 ReservedVector[16]; // Reserved for ARM ResetVector, 0xFFs on x86/x86-64 machines
|
||||
UINT32 Signature; // 0x0FF0A55A
|
||||
} FLASH_DESCRIPTOR_HEADER;
|
||||
|
||||
// Flash descriptor signature
|
||||
#define FLASH_DESCRIPTOR_SIGNATURE 0x0FF0A55A
|
||||
|
||||
// Descriptor region size
|
||||
#define FLASH_DESCRIPTOR_SIZE 0x1000
|
||||
|
||||
// Maximum base value in descriptor map
|
||||
#define FLASH_DESCRIPTOR_MAX_BASE 0xE0
|
||||
|
||||
// Descriptor version was reserved in older firmware
|
||||
#define FLASH_DESCRIPTOR_VERSION_INVALID 0xFFFFFFFF
|
||||
// The only known version found in Coffee Lake
|
||||
#define FLASH_DESCRIPTOR_VERSION_MAJOR 1
|
||||
#define FLASH_DESCRIPTOR_VERSION_MINOR 0
|
||||
|
||||
// Descriptor version present in Coffee Lake and newer
|
||||
typedef struct _FLASH_DESCRIPTOR_VERSION {
|
||||
UINT32 Reserved : 14;
|
||||
UINT32 Minor : 7;
|
||||
UINT32 Major : 11;
|
||||
} FLASH_DESCRIPTOR_VERSION;
|
||||
|
||||
// Descriptor map
|
||||
// Base fields are storing bits [11:4] of actual base addresses, all other bits are 0
|
||||
typedef struct FLASH_DESCRIPTOR_MAP_ {
|
||||
// FLMAP0
|
||||
UINT32 ComponentBase : 8;
|
||||
UINT32 NumberOfFlashChips : 2; // Zero-based number of flash chips installed on board
|
||||
UINT32 : 6;
|
||||
UINT32 RegionBase : 8;
|
||||
UINT32 NumberOfRegions : 3; // Reserved in v2 descriptor
|
||||
UINT32 : 5;
|
||||
// FLMAP 1
|
||||
UINT32 MasterBase : 8;
|
||||
UINT32 NumberOfMasters : 2; // Zero-based number of flash masters
|
||||
UINT32 : 6;
|
||||
UINT32 PchStrapsBase : 8;
|
||||
UINT32 NumberOfPchStraps : 8; // One-based number of UINT32s to read as PCH straps, min=0, max=255 (1 Kb)
|
||||
// FLMAP 2
|
||||
UINT32 ProcStrapsBase : 8;
|
||||
UINT32 NumberOfProcStraps : 8; // One-based number of UINT32s to read as processor straps, min=0, max=255 (1 Kb)
|
||||
UINT32 : 16;
|
||||
// FLMAP 3
|
||||
UINT32 DescriptorVersion; // Reserved prior to Coffee Lake
|
||||
} FLASH_DESCRIPTOR_MAP;
|
||||
|
||||
// Component section
|
||||
// Flash parameters DWORD structure
|
||||
typedef struct FLASH_PARAMETERS_ {
|
||||
UINT8 FirstChipDensity : 4;
|
||||
UINT8 SecondChipDensity : 4;
|
||||
UINT8 : 8;
|
||||
UINT8 : 1;
|
||||
UINT8 ReadClockFrequency : 3; // Hardcoded value of 20 Mhz (000b) in v1 descriptors
|
||||
UINT8 FastReadEnabled : 1;
|
||||
UINT8 FastReadFrequency : 3;
|
||||
UINT8 FlashWriteFrequency : 3;
|
||||
UINT8 FlashReadStatusFrequency : 3;
|
||||
UINT8 DualOutputFastReadSupported : 1;
|
||||
UINT8 : 1;
|
||||
} FLASH_PARAMETERS;
|
||||
|
||||
// Flash densities
|
||||
#define FLASH_DENSITY_512KB 0x00
|
||||
#define FLASH_DENSITY_1MB 0x01
|
||||
#define FLASH_DENSITY_2MB 0x02
|
||||
#define FLASH_DENSITY_4MB 0x03
|
||||
#define FLASH_DENSITY_8MB 0x04
|
||||
#define FLASH_DENSITY_16MB 0x05
|
||||
#define FLASH_DENSITY_32MB 0x06
|
||||
#define FLASH_DENSITY_64MB 0x07
|
||||
#define FLASH_DENSITY_UNUSED 0x0F
|
||||
|
||||
// Flash frequencies
|
||||
#define FLASH_FREQUENCY_20MHZ 0x00
|
||||
#define FLASH_FREQUENCY_33MHZ 0x01
|
||||
#define FLASH_FREQUENCY_48MHZ 0x02
|
||||
#define FLASH_FREQUENCY_50MHZ_30MHZ 0x04
|
||||
#define FLASH_FREQUENCY_17MHZ 0x06
|
||||
|
||||
// Component section structure
|
||||
typedef struct FLASH_DESCRIPTOR_COMPONENT_SECTION_ {
|
||||
FLASH_PARAMETERS FlashParameters;
|
||||
UINT8 InvalidInstruction0; // Instructions for SPI chip, that must not be executed, like FLASH ERASE
|
||||
UINT8 InvalidInstruction1; //
|
||||
UINT8 InvalidInstruction2; //
|
||||
UINT8 InvalidInstruction3; //
|
||||
UINT16 PartitionBoundary; // Upper 16 bit of partition boundary address. Default is 0x0000, which makes the boundary to be 0x00001000
|
||||
UINT16 : 16;
|
||||
} FLASH_DESCRIPTOR_COMPONENT_SECTION;
|
||||
|
||||
// Region section
|
||||
// All base and limit register are storing upper part of actual UINT32 base and limit
|
||||
// If limit is zero - region is not present
|
||||
typedef struct FLASH_DESCRIPTOR_REGION_SECTION_ {
|
||||
UINT16 DescriptorBase; // Descriptor
|
||||
UINT16 DescriptorLimit; //
|
||||
UINT16 BiosBase; // BIOS
|
||||
UINT16 BiosLimit; //
|
||||
UINT16 MeBase; // Management Engine
|
||||
UINT16 MeLimit; //
|
||||
UINT16 GbeBase; // Gigabit Ethernet
|
||||
UINT16 GbeLimit; //
|
||||
UINT16 PdrBase; // Platform Data
|
||||
UINT16 PdrLimit; //
|
||||
UINT16 DevExp1Base; // Device Expansion 1
|
||||
UINT16 DevExp1Limit; //
|
||||
UINT16 Bios2Base; // Secondary BIOS
|
||||
UINT16 Bios2Limit; //
|
||||
UINT16 MicrocodeBase; // CPU microcode
|
||||
UINT16 MicrocodeLimit; //
|
||||
UINT16 EcBase; // Embedded Controller
|
||||
UINT16 EcLimit; //
|
||||
UINT16 DevExp2Base; // Device Expansion 2
|
||||
UINT16 DevExp2Limit; //
|
||||
UINT16 IeBase; // Innovation Engine
|
||||
UINT16 IeLimit; //
|
||||
UINT16 Tgbe1Base; // 10 Gigabit Ethernet 1
|
||||
UINT16 Tgbe1Limit; //
|
||||
UINT16 Tgbe2Base; // 10 Gigabit Ethernet 2
|
||||
UINT16 Tgbe2Limit; //
|
||||
UINT16 Reserved1Base; // Reserved 1
|
||||
UINT16 Reserved1Limit; //
|
||||
UINT16 Reserved2Base; // Reserved 2
|
||||
UINT16 Reserved2Limit; //
|
||||
UINT16 PttBase; // Platform Trust Technology
|
||||
UINT16 PttLimit; //
|
||||
} FLASH_DESCRIPTOR_REGION_SECTION;
|
||||
|
||||
// Master section
|
||||
typedef struct FLASH_DESCRIPTOR_MASTER_SECTION_ {
|
||||
UINT16 BiosId;
|
||||
UINT8 BiosRead;
|
||||
UINT8 BiosWrite;
|
||||
UINT16 MeId;
|
||||
UINT8 MeRead;
|
||||
UINT8 MeWrite;
|
||||
UINT16 GbeId;
|
||||
UINT8 GbeRead;
|
||||
UINT8 GbeWrite;
|
||||
} FLASH_DESCRIPTOR_MASTER_SECTION;
|
||||
|
||||
// Master section v2 (Skylake+)
|
||||
typedef struct FLASH_DESCRIPTOR_MASTER_SECTION_V2_ {
|
||||
UINT32 : 8;
|
||||
UINT32 BiosRead : 12;
|
||||
UINT32 BiosWrite : 12;
|
||||
UINT32 : 8;
|
||||
UINT32 MeRead : 12;
|
||||
UINT32 MeWrite : 12;
|
||||
UINT32 : 8;
|
||||
UINT32 GbeRead : 12;
|
||||
UINT32 GbeWrite : 12;
|
||||
UINT32 : 32;
|
||||
UINT32 : 8;
|
||||
UINT32 EcRead : 12;
|
||||
UINT32 EcWrite : 12;
|
||||
} FLASH_DESCRIPTOR_MASTER_SECTION_V2;
|
||||
|
||||
// Region access bits in master section
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_DESC 0x01
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_BIOS 0x02
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_ME 0x04
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_GBE 0x08
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_PDR 0x10
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_EC 0x20
|
||||
|
||||
// Base address of descriptor upper map
|
||||
#define FLASH_DESCRIPTOR_UPPER_MAP_BASE 0x0EFC
|
||||
|
||||
// Descriptor upper map structure
|
||||
typedef struct FLASH_DESCRIPTOR_UPPER_MAP_ {
|
||||
UINT8 VsccTableBase; // Base address of VSCC Table for ME, bits [11:4]
|
||||
UINT8 VsccTableSize; // Counted in UINT32s
|
||||
UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen
|
||||
} FLASH_DESCRIPTOR_UPPER_MAP;
|
||||
|
||||
// VSCC table entry structure
|
||||
typedef struct VSCC_TABLE_ENTRY_ {
|
||||
UINT8 VendorId; // JEDEC VendorID byte
|
||||
UINT8 DeviceId0; // JEDEC DeviceID first byte
|
||||
UINT8 DeviceId1; // JEDEC DeviceID second byte
|
||||
UINT8 ReservedZero; // Reserved, must be zero
|
||||
UINT32 VsccRegisterValue; // VSCC register value
|
||||
} VSCC_TABLE_ENTRY;
|
||||
|
||||
// Base address and size of OEM section
|
||||
#define FLASH_DESCRIPTOR_OEM_SECTION_BASE 0x0F00
|
||||
#define FLASH_DESCRIPTOR_OEM_SECTION_SIZE 0x100
|
||||
|
||||
// Restore previous packing rules
|
||||
#pragma pack(pop)
|
||||
|
||||
// Calculate address of data structure addressed by descriptor address format
|
||||
// 8 bit base or limit
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <iostream>
|
||||
|
||||
#include "descriptor.h"
|
||||
#include "intel_descriptor.h"
|
||||
#include "ffs.h"
|
||||
#include "gbe.h"
|
||||
#include "me.h"
|
||||
|
@ -258,545 +259,33 @@ USTATUS FfsParser::parseCapsule(const UByteArray & capsule, const UINT32 localOf
|
|||
capsuleHeaderSize, capsuleHeaderSize,
|
||||
capsuleHeader->CapsuleHeader.CapsuleImageSize - capsuleHeaderSize, capsuleHeader->CapsuleHeader.CapsuleImageSize - capsuleHeaderSize,
|
||||
capsuleHeader->CapsuleHeader.Flags);
|
||||
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Capsule, signedCapsule ? Subtypes::AptioSignedCapsule : Subtypes::AptioUnsignedCapsule, name, UString(), info, header, body, UByteArray(), Fixed, parent);
|
||||
|
||||
|
||||
// Show message about possible Aptio signature break
|
||||
if (signedCapsule) {
|
||||
msg(usprintf("%s: Aptio capsule signature may become invalid after image modifications", __FUNCTION__), index);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Capsule present
|
||||
if (capsuleHeaderSize > 0) {
|
||||
UByteArray image = capsule.mid(capsuleHeaderSize);
|
||||
UModelIndex imageIndex;
|
||||
|
||||
|
||||
// Try parsing as Intel image
|
||||
if (U_SUCCESS == parseIntelImage(image, capsuleHeaderSize, index, imageIndex)) {
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
// Parse as generic image
|
||||
return parseGenericImage(image, capsuleHeaderSize, index, imageIndex);
|
||||
}
|
||||
|
||||
|
||||
return U_ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check for buffer size to be greater or equal to descriptor region size
|
||||
if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) {
|
||||
msg(usprintf("%s: input file is smaller than minimum descriptor size of %Xh (%u) bytes", __FUNCTION__, FLASH_DESCRIPTOR_SIZE, FLASH_DESCRIPTOR_SIZE));
|
||||
return U_ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Store the beginning of descriptor as descriptor base address
|
||||
const FLASH_DESCRIPTOR_HEADER* descriptor = (const FLASH_DESCRIPTOR_HEADER*)intelImage.constData();
|
||||
|
||||
// Check descriptor signature
|
||||
if (descriptor->Signature != FLASH_DESCRIPTOR_SIGNATURE) {
|
||||
return U_ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Parse descriptor map
|
||||
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)((UINT8*)descriptor + sizeof(FLASH_DESCRIPTOR_HEADER));
|
||||
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)((UINT8*)descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
|
||||
|
||||
// Check sanity of base values
|
||||
if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||
|| descriptorMap->MasterBase == descriptorMap->RegionBase
|
||||
|| descriptorMap->MasterBase == descriptorMap->ComponentBase) {
|
||||
msg(usprintf("%s: invalid descriptor master base %02Xh", __FUNCTION__, descriptorMap->MasterBase));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorMap->RegionBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||
|| descriptorMap->RegionBase == descriptorMap->ComponentBase) {
|
||||
msg(usprintf("%s: invalid descriptor region base %02Xh", __FUNCTION__, descriptorMap->RegionBase));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorMap->ComponentBase > FLASH_DESCRIPTOR_MAX_BASE) {
|
||||
msg(usprintf("%s: invalid descriptor component base %02Xh", __FUNCTION__, descriptorMap->ComponentBase));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->RegionBase);
|
||||
const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->ComponentBase);
|
||||
|
||||
UINT8 descriptorVersion = 2;
|
||||
// Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency
|
||||
if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_20MHZ)
|
||||
descriptorVersion = 1;
|
||||
|
||||
// Regions
|
||||
std::vector<REGION_INFO> regions;
|
||||
|
||||
// ME region
|
||||
REGION_INFO me;
|
||||
me.type = Subtypes::MeRegion;
|
||||
me.offset = 0;
|
||||
me.length = 0;
|
||||
if (regionSection->MeLimit) {
|
||||
me.offset = calculateRegionOffset(regionSection->MeBase);
|
||||
me.length = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit);
|
||||
if ((UINT32)intelImage.size() < me.offset + me.length) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, me.type)
|
||||
+ UString(" region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image"),
|
||||
index);
|
||||
return U_TRUNCATED_IMAGE;
|
||||
}
|
||||
me.data = intelImage.mid(me.offset, me.length);
|
||||
regions.push_back(me);
|
||||
}
|
||||
|
||||
// BIOS region
|
||||
if (regionSection->BiosLimit) {
|
||||
REGION_INFO bios;
|
||||
bios.type = Subtypes::BiosRegion;
|
||||
bios.offset = calculateRegionOffset(regionSection->BiosBase);
|
||||
bios.length = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit);
|
||||
|
||||
// Check for Gigabyte specific descriptor map
|
||||
if (bios.length == (UINT32)intelImage.size()) {
|
||||
if (!me.offset) {
|
||||
msg(usprintf("%s: can't determine BIOS region start from Gigabyte-specific descriptor", __FUNCTION__));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Use ME region end as BIOS region offset
|
||||
bios.offset = me.offset + me.length;
|
||||
bios.length = (UINT32)intelImage.size() - bios.offset;
|
||||
}
|
||||
|
||||
if ((UINT32)intelImage.size() < bios.offset + bios.length) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, bios.type)
|
||||
+ UString(" region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image"),
|
||||
index);
|
||||
return U_TRUNCATED_IMAGE;
|
||||
}
|
||||
bios.data = intelImage.mid(bios.offset, bios.length);
|
||||
regions.push_back(bios);
|
||||
}
|
||||
else {
|
||||
msg(usprintf("%s: descriptor parsing failed, BIOS region not found in descriptor", __FUNCTION__));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
// Add all other regions
|
||||
for (UINT8 i = Subtypes::GbeRegion; i <= Subtypes::PttRegion; i++) {
|
||||
if (descriptorVersion == 1 && i == Subtypes::MicrocodeRegion)
|
||||
break; // Do not parse Microcode and other following regions for legacy descriptors
|
||||
|
||||
const UINT16* RegionBase = ((const UINT16*)regionSection) + 2 * i;
|
||||
const UINT16* RegionLimit = ((const UINT16*)regionSection) + 2 * i + 1;
|
||||
if (*RegionLimit && !(*RegionBase == 0xFFFF && *RegionLimit == 0xFFFF)) {
|
||||
REGION_INFO region;
|
||||
region.type = i;
|
||||
region.offset = calculateRegionOffset(*RegionBase);
|
||||
region.length = calculateRegionSize(*RegionBase, *RegionLimit);
|
||||
if (region.length != 0) {
|
||||
if ((UINT32)intelImage.size() < region.offset + region.length) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, region.type)
|
||||
+ UString(" region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image"),
|
||||
index);
|
||||
return U_TRUNCATED_IMAGE;
|
||||
}
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
regions.push_back(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Regions can not be empty here
|
||||
if (regions.empty()) {
|
||||
msg(usprintf("%s: descriptor parsing failed, no regions found", __FUNCTION__));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
// Sort regions in ascending order
|
||||
std::sort(regions.begin(), regions.end());
|
||||
|
||||
// Check for intersections and paddings between regions
|
||||
REGION_INFO region;
|
||||
// Check intersection with the descriptor
|
||||
if (regions.front().offset < FLASH_DESCRIPTOR_SIZE) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, regions.front().type)
|
||||
+ UString(" region has intersection with flash descriptor"),
|
||||
index);
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Check for padding between descriptor and the first region
|
||||
else if (regions.front().offset > FLASH_DESCRIPTOR_SIZE) {
|
||||
region.offset = FLASH_DESCRIPTOR_SIZE;
|
||||
region.length = regions.front().offset - FLASH_DESCRIPTOR_SIZE;
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
regions.insert(regions.begin(), region);
|
||||
}
|
||||
// Check for intersections/paddings between regions
|
||||
for (size_t i = 1; i < regions.size(); i++) {
|
||||
UINT32 previousRegionEnd = regions[i-1].offset + regions[i-1].length;
|
||||
// Check for intersection with previous region
|
||||
if (regions[i].offset < previousRegionEnd) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, regions[i].type)
|
||||
+ UString(" region has intersection with ") + itemSubtypeToUString(Types::Region, regions[i - 1].type)
|
||||
+ UString(" region"),
|
||||
index);
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Check for padding between current and previous regions
|
||||
else if (regions[i].offset > previousRegionEnd) {
|
||||
region.offset = previousRegionEnd;
|
||||
region.length = regions[i].offset - previousRegionEnd;
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
std::vector<REGION_INFO>::iterator iter = regions.begin();
|
||||
std::advance(iter, i);
|
||||
regions.insert(iter, region);
|
||||
}
|
||||
}
|
||||
// Check for padding after the last region
|
||||
if ((UINT64)regions.back().offset + (UINT64)regions.back().length < (UINT64)intelImage.size()) {
|
||||
region.offset = regions.back().offset + regions.back().length;
|
||||
region.length = (UINT32)(intelImage.size() - region.offset);
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
regions.push_back(region);
|
||||
}
|
||||
|
||||
// Region map is consistent
|
||||
|
||||
// Intel image
|
||||
UString name("Intel image");
|
||||
UString info = usprintf("Full size: %Xh (%u)\nFlash chips: %u\nRegions: %u\nMasters: %u\nPCH straps: %u\nPROC straps: %u",
|
||||
(UINT32)intelImage.size(), (UINT32)intelImage.size(),
|
||||
descriptorMap->NumberOfFlashChips + 1, //
|
||||
descriptorMap->NumberOfRegions + 1, // Zero-based numbers in storage
|
||||
descriptorMap->NumberOfMasters + 1, //
|
||||
descriptorMap->NumberOfPchStraps,
|
||||
descriptorMap->NumberOfProcStraps);
|
||||
|
||||
// Set image base
|
||||
imageBase = model->base(parent) + localOffset;
|
||||
|
||||
// Add Intel image tree item
|
||||
index = model->addItem(localOffset, Types::Image, Subtypes::IntelImage, name, UString(), info, UByteArray(), intelImage, UByteArray(), Fixed, parent);
|
||||
|
||||
// Descriptor
|
||||
// Get descriptor info
|
||||
UByteArray body = intelImage.left(FLASH_DESCRIPTOR_SIZE);
|
||||
name = UString("Descriptor region");
|
||||
info = usprintf("ReservedVector:\n%02X %02X %02X %02X %02X %02X %02X %02X\n"
|
||||
"%02X %02X %02X %02X %02X %02X %02X %02X\nFull size: %Xh (%u)",
|
||||
descriptor->ReservedVector[0], descriptor->ReservedVector[1], descriptor->ReservedVector[2], descriptor->ReservedVector[3],
|
||||
descriptor->ReservedVector[4], descriptor->ReservedVector[5], descriptor->ReservedVector[6], descriptor->ReservedVector[7],
|
||||
descriptor->ReservedVector[8], descriptor->ReservedVector[9], descriptor->ReservedVector[10], descriptor->ReservedVector[11],
|
||||
descriptor->ReservedVector[12], descriptor->ReservedVector[13], descriptor->ReservedVector[14], descriptor->ReservedVector[15],
|
||||
FLASH_DESCRIPTOR_SIZE, FLASH_DESCRIPTOR_SIZE);
|
||||
|
||||
// Add offsets of actual regions
|
||||
for (size_t i = 0; i < regions.size(); i++) {
|
||||
if (regions[i].type != Subtypes::ZeroPadding && regions[i].type != Subtypes::OnePadding && regions[i].type != Subtypes::DataPadding)
|
||||
info += "\n" + itemSubtypeToUString(Types::Region, regions[i].type)
|
||||
+ usprintf(" region offset: %Xh", regions[i].offset + localOffset);
|
||||
}
|
||||
|
||||
// Region access settings
|
||||
if (descriptorVersion == 1) {
|
||||
const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->MasterBase);
|
||||
info += UString("\nRegion access settings:");
|
||||
info += usprintf("\nBIOS: %02Xh %02Xh ME: %02Xh %02Xh\nGbE: %02Xh %02Xh",
|
||||
masterSection->BiosRead,
|
||||
masterSection->BiosWrite,
|
||||
masterSection->MeRead,
|
||||
masterSection->MeWrite,
|
||||
masterSection->GbeRead,
|
||||
masterSection->GbeWrite);
|
||||
|
||||
// BIOS access table
|
||||
info += UString("\nBIOS access table:")
|
||||
+ UString("\n Read Write")
|
||||
+ usprintf("\nDesc %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ");
|
||||
info += UString("\nBIOS Yes Yes")
|
||||
+ usprintf("\nME %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ");
|
||||
info += usprintf("\nGbE %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ");
|
||||
info += usprintf("\nPDR %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ");
|
||||
}
|
||||
else if (descriptorVersion == 2) {
|
||||
const FLASH_DESCRIPTOR_MASTER_SECTION_V2* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION_V2*)calculateAddress8((UINT8*)descriptor, descriptorMap->MasterBase);
|
||||
info += UString("\nRegion access settings:");
|
||||
info += usprintf("\nBIOS: %03Xh %03Xh ME: %03Xh %03Xh\nGbE: %03Xh %03Xh EC: %03Xh %03Xh",
|
||||
masterSection->BiosRead,
|
||||
masterSection->BiosWrite,
|
||||
masterSection->MeRead,
|
||||
masterSection->MeWrite,
|
||||
masterSection->GbeRead,
|
||||
masterSection->GbeWrite,
|
||||
masterSection->EcRead,
|
||||
masterSection->EcWrite);
|
||||
|
||||
// BIOS access table
|
||||
info += UString("\nBIOS access table:")
|
||||
+ UString("\n Read Write")
|
||||
+ usprintf("\nDesc %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ");
|
||||
info += UString("\nBIOS Yes Yes")
|
||||
+ usprintf("\nME %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ");
|
||||
info += usprintf("\nGbE %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ");
|
||||
info += usprintf("\nPDR %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ");
|
||||
info += usprintf("\nEC %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ");
|
||||
|
||||
// Prepend descriptor version if present
|
||||
if (descriptorMap->DescriptorVersion != FLASH_DESCRIPTOR_VERSION_INVALID) {
|
||||
const FLASH_DESCRIPTOR_VERSION* version = (const FLASH_DESCRIPTOR_VERSION*)&descriptorMap->DescriptorVersion;
|
||||
UString versionStr = usprintf("Flash descriptor version: %d.%d", version->Major, version->Minor);
|
||||
if (version->Major != FLASH_DESCRIPTOR_VERSION_MAJOR || version->Minor != FLASH_DESCRIPTOR_VERSION_MINOR) {
|
||||
versionStr += ", unknown";
|
||||
msg(usprintf("%s: unknown flash descriptor version %d.%d", __FUNCTION__, version->Major, version->Minor));
|
||||
}
|
||||
info = versionStr + "\n" + info;
|
||||
}
|
||||
}
|
||||
|
||||
// VSCC table
|
||||
const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)((UINT8*)descriptor + ((UINT16)upperMap->VsccTableBase << 4));
|
||||
info += UString("\nFlash chips in VSCC table:");
|
||||
UINT8 vsscTableSize = upperMap->VsccTableSize * sizeof(UINT32) / sizeof(VSCC_TABLE_ENTRY);
|
||||
for (UINT8 i = 0; i < vsscTableSize; i++) {
|
||||
UString jedecId = jedecIdToUString(vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1);
|
||||
info += usprintf("\n%02X%02X%02X (", vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1)
|
||||
+ jedecId
|
||||
+ UString(")");
|
||||
if (jedecId.startsWith("Unknown")) {
|
||||
msg(usprintf("%s: SPI flash with unknown JEDEC ID %02X%02X%02X found in VSCC table", __FUNCTION__,
|
||||
vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1), index);
|
||||
}
|
||||
vsccTableEntry++;
|
||||
}
|
||||
|
||||
// Add descriptor tree item
|
||||
UModelIndex regionIndex = model->addItem(localOffset, Types::Region, Subtypes::DescriptorRegion, name, UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
|
||||
|
||||
// Parse regions
|
||||
USTATUS result = U_SUCCESS;
|
||||
USTATUS parseResult = U_SUCCESS;
|
||||
for (size_t i = 0; i < regions.size(); i++) {
|
||||
region = regions[i];
|
||||
switch (region.type) {
|
||||
case Subtypes::BiosRegion:
|
||||
result = parseBiosRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::MeRegion:
|
||||
result = parseMeRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::GbeRegion:
|
||||
result = parseGbeRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::PdrRegion:
|
||||
result = parsePdrRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::DevExp1Region:
|
||||
result = parseDevExp1Region(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::Bios2Region:
|
||||
case Subtypes::MicrocodeRegion:
|
||||
case Subtypes::EcRegion:
|
||||
case Subtypes::DevExp2Region:
|
||||
case Subtypes::IeRegion:
|
||||
case Subtypes::Tgbe1Region:
|
||||
case Subtypes::Tgbe2Region:
|
||||
case Subtypes::Reserved1Region:
|
||||
case Subtypes::Reserved2Region:
|
||||
case Subtypes::PttRegion:
|
||||
result = parseGenericRegion(region.type, region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::ZeroPadding:
|
||||
case Subtypes::OnePadding:
|
||||
case Subtypes::DataPadding: {
|
||||
// Add padding between regions
|
||||
UByteArray padding = intelImage.mid(region.offset, region.length);
|
||||
|
||||
// Get info
|
||||
name = UString("Padding");
|
||||
info = usprintf("Full size: %Xh (%u)",
|
||||
(UINT32)padding.size(), (UINT32)padding.size());
|
||||
|
||||
// Add tree item
|
||||
regionIndex = model->addItem(region.offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
||||
result = U_SUCCESS;
|
||||
} break;
|
||||
default:
|
||||
msg(usprintf("%s: region of unknown type found", __FUNCTION__), index);
|
||||
result = U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Store the first failed result as a final result
|
||||
if (!parseResult && result) {
|
||||
parseResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
return parseResult;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parseGbeRegion(const UByteArray & gbe, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (gbe.isEmpty())
|
||||
return U_EMPTY_REGION;
|
||||
if ((UINT32)gbe.size() < GBE_VERSION_OFFSET + sizeof(GBE_VERSION))
|
||||
return U_INVALID_REGION;
|
||||
|
||||
// Get info
|
||||
UString name("GbE region");
|
||||
const GBE_MAC_ADDRESS* mac = (const GBE_MAC_ADDRESS*)gbe.constData();
|
||||
const GBE_VERSION* version = (const GBE_VERSION*)(gbe.constData() + GBE_VERSION_OFFSET);
|
||||
UString info = usprintf("Full size: %Xh (%u)\nMAC: %02X:%02X:%02X:%02X:%02X:%02X\nVersion: %u.%u",
|
||||
(UINT32)gbe.size(), (UINT32)gbe.size(),
|
||||
mac->vendor[0], mac->vendor[1], mac->vendor[2],
|
||||
mac->device[0], mac->device[1], mac->device[2],
|
||||
version->major,
|
||||
version->minor);
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Region, Subtypes::GbeRegion, name, UString(), info, UByteArray(), gbe, UByteArray(), Fixed, parent);
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (me.isEmpty())
|
||||
return U_EMPTY_REGION;
|
||||
|
||||
// Get info
|
||||
UString name("ME region");
|
||||
UString info = usprintf("Full size: %Xh (%u)", (UINT32)me.size(), (UINT32)me.size());
|
||||
|
||||
// Parse region
|
||||
bool versionFound = true;
|
||||
bool emptyRegion = false;
|
||||
// Check for empty region
|
||||
if (me.size() == me.count('\xFF') || me.size() == me.count('\x00')) {
|
||||
// Further parsing not needed
|
||||
emptyRegion = true;
|
||||
info += ("\nState: empty");
|
||||
}
|
||||
else {
|
||||
// Search for new signature
|
||||
UINT32 sig2Value = ME_VERSION_SIGNATURE2;
|
||||
UByteArray sig2((const char*)&sig2Value, sizeof(sig2Value));
|
||||
INT32 versionOffset = (INT32)me.indexOf(sig2);
|
||||
if (versionOffset < 0) { // New signature not found
|
||||
// Search for old signature
|
||||
UINT32 sigValue = ME_VERSION_SIGNATURE;
|
||||
UByteArray sig((const char*)&sigValue, sizeof(sigValue));
|
||||
versionOffset = (INT32)me.indexOf(sig);
|
||||
if (versionOffset < 0) {
|
||||
info += ("\nVersion: unknown");
|
||||
versionFound = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check sanity
|
||||
if ((UINT32)me.size() < (UINT32)versionOffset + sizeof(ME_VERSION))
|
||||
return U_INVALID_REGION;
|
||||
|
||||
// Add version information
|
||||
if (versionFound) {
|
||||
const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset);
|
||||
info += usprintf("\nVersion: %u.%u.%u.%u",
|
||||
version->Major,
|
||||
version->Minor,
|
||||
version->Bugfix,
|
||||
version->Build);
|
||||
}
|
||||
}
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Region, Subtypes::MeRegion, name, UString(), info, UByteArray(), me, UByteArray(), Fixed, parent);
|
||||
|
||||
// Show messages
|
||||
if (emptyRegion) {
|
||||
msg(usprintf("%s: ME region is empty", __FUNCTION__), index);
|
||||
}
|
||||
else if (!versionFound) {
|
||||
msg(usprintf("%s: ME version is unknown, it can be damaged", __FUNCTION__), index);
|
||||
}
|
||||
else {
|
||||
meParser->parseMeRegionBody(index);
|
||||
}
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (pdr.isEmpty())
|
||||
return U_EMPTY_REGION;
|
||||
|
||||
// Get info
|
||||
UString name("PDR region");
|
||||
UString info = usprintf("Full size: %Xh (%u)", (UINT32)pdr.size(), (UINT32)pdr.size());
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Region, Subtypes::PdrRegion, name, UString(), info, UByteArray(), pdr, UByteArray(), Fixed, parent);
|
||||
|
||||
// Parse PDR region as BIOS space
|
||||
USTATUS result = parseRawArea(index);
|
||||
if (result && result != U_VOLUMES_NOT_FOUND && result != U_INVALID_VOLUME && result != U_STORES_NOT_FOUND)
|
||||
return result;
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parseDevExp1Region(const UByteArray & devExp1, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (devExp1.isEmpty())
|
||||
return U_EMPTY_REGION;
|
||||
|
||||
// Get info
|
||||
UString name("DevExp1 region");
|
||||
UString info = usprintf("Full size: %Xh (%u)", (UINT32)devExp1.size(), (UINT32)devExp1.size());
|
||||
|
||||
bool emptyRegion = false;
|
||||
// Check for empty region
|
||||
if (devExp1.size() == devExp1.count('\xFF') || devExp1.size() == devExp1.count('\x00')) {
|
||||
// Further parsing not needed
|
||||
emptyRegion = true;
|
||||
info += ("\nState: empty");
|
||||
}
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Region, Subtypes::DevExp1Region, name, UString(), info, UByteArray(), devExp1, UByteArray(), Fixed, parent);
|
||||
|
||||
if (!emptyRegion) {
|
||||
meParser->parseMeRegionBody(index);
|
||||
}
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parseGenericRegion(const UINT8 subtype, const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
|
|
|
@ -126,9 +126,10 @@ private:
|
|||
USTATUS performFirstPass(const UByteArray & imageFile, 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 parseGenericImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
|
||||
// Intel specific
|
||||
USTATUS parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseBpdtRegion(const UByteArray & region, const UINT32 localOffset, const UINT32 sbpdtOffsetFixup, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseCpdRegion(const UByteArray & region, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseCpdExtensionsArea(const UModelIndex & index, const UINT32 localOffset);
|
||||
|
@ -143,6 +144,7 @@ private:
|
|||
USTATUS parseSectionHeader(const UByteArray & section, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index, const bool insertIntoTree);
|
||||
USTATUS parseSectionBody(const UModelIndex & index);
|
||||
|
||||
// Intel specific
|
||||
USTATUS parseGbeRegion(const UByteArray & gbe, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseMeRegion(const UByteArray & me, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
USTATUS parseBiosRegion(const UByteArray & bios, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index);
|
||||
|
|
549
common/ffsparser_intel.cpp
Normal file
549
common/ffsparser_intel.cpp
Normal file
|
@ -0,0 +1,549 @@
|
|||
/* ffsparser_intel.cpp
|
||||
|
||||
Copyright (c) 2018, 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,
|
||||
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
*/
|
||||
|
||||
#include "ffsparser.h"
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include "descriptor.h"
|
||||
#include "intel_descriptor.h"
|
||||
#include "ffs.h"
|
||||
#include "gbe.h"
|
||||
#include "me.h"
|
||||
#include "intel_fit.h"
|
||||
#include "nvram.h"
|
||||
#include "peimage.h"
|
||||
#include "parsingdata.h"
|
||||
#include "types.h"
|
||||
#include "utility.h"
|
||||
|
||||
#include "nvramparser.h"
|
||||
#include "meparser.h"
|
||||
#include "fitparser.h"
|
||||
|
||||
#include "digest/sha1.h"
|
||||
#include "digest/sha2.h"
|
||||
#include "digest/sm3.h"
|
||||
|
||||
USTATUS FfsParser::parseIntelImage(const UByteArray & intelImage, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check for buffer size to be greater or equal to descriptor region size
|
||||
if (intelImage.size() < FLASH_DESCRIPTOR_SIZE) {
|
||||
msg(usprintf("%s: input file is smaller than minimum descriptor size of %Xh (%u) bytes", __FUNCTION__, FLASH_DESCRIPTOR_SIZE, FLASH_DESCRIPTOR_SIZE));
|
||||
return U_ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Store the beginning of descriptor as descriptor base address
|
||||
const FLASH_DESCRIPTOR_HEADER* descriptor = (const FLASH_DESCRIPTOR_HEADER*)intelImage.constData();
|
||||
|
||||
// Check descriptor signature
|
||||
if (descriptor->Signature != FLASH_DESCRIPTOR_SIGNATURE) {
|
||||
return U_ITEM_NOT_FOUND;
|
||||
}
|
||||
|
||||
// Parse descriptor map
|
||||
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)((UINT8*)descriptor + sizeof(FLASH_DESCRIPTOR_HEADER));
|
||||
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)((UINT8*)descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
|
||||
|
||||
// Check sanity of base values
|
||||
if (descriptorMap->MasterBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||
|| descriptorMap->MasterBase == descriptorMap->RegionBase
|
||||
|| descriptorMap->MasterBase == descriptorMap->ComponentBase) {
|
||||
msg(usprintf("%s: invalid descriptor master base %02Xh", __FUNCTION__, descriptorMap->MasterBase));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorMap->RegionBase > FLASH_DESCRIPTOR_MAX_BASE
|
||||
|| descriptorMap->RegionBase == descriptorMap->ComponentBase) {
|
||||
msg(usprintf("%s: invalid descriptor region base %02Xh", __FUNCTION__, descriptorMap->RegionBase));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
if (descriptorMap->ComponentBase > FLASH_DESCRIPTOR_MAX_BASE) {
|
||||
msg(usprintf("%s: invalid descriptor component base %02Xh", __FUNCTION__, descriptorMap->ComponentBase));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->RegionBase);
|
||||
const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->ComponentBase);
|
||||
|
||||
UINT8 descriptorVersion = 2;
|
||||
// Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency
|
||||
if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_20MHZ)
|
||||
descriptorVersion = 1;
|
||||
|
||||
// Regions
|
||||
std::vector<REGION_INFO> regions;
|
||||
|
||||
// ME region
|
||||
REGION_INFO me;
|
||||
me.type = Subtypes::MeRegion;
|
||||
me.offset = 0;
|
||||
me.length = 0;
|
||||
if (regionSection->MeLimit) {
|
||||
me.offset = calculateRegionOffset(regionSection->MeBase);
|
||||
me.length = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit);
|
||||
if ((UINT32)intelImage.size() < me.offset + me.length) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, me.type)
|
||||
+ UString(" region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image"),
|
||||
index);
|
||||
return U_TRUNCATED_IMAGE;
|
||||
}
|
||||
me.data = intelImage.mid(me.offset, me.length);
|
||||
regions.push_back(me);
|
||||
}
|
||||
|
||||
// BIOS region
|
||||
if (regionSection->BiosLimit) {
|
||||
REGION_INFO bios;
|
||||
bios.type = Subtypes::BiosRegion;
|
||||
bios.offset = calculateRegionOffset(regionSection->BiosBase);
|
||||
bios.length = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit);
|
||||
|
||||
// Check for Gigabyte specific descriptor map
|
||||
if (bios.length == (UINT32)intelImage.size()) {
|
||||
if (!me.offset) {
|
||||
msg(usprintf("%s: can't determine BIOS region start from Gigabyte-specific descriptor", __FUNCTION__));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Use ME region end as BIOS region offset
|
||||
bios.offset = me.offset + me.length;
|
||||
bios.length = (UINT32)intelImage.size() - bios.offset;
|
||||
}
|
||||
|
||||
if ((UINT32)intelImage.size() < bios.offset + bios.length) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, bios.type)
|
||||
+ UString(" region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image"),
|
||||
index);
|
||||
return U_TRUNCATED_IMAGE;
|
||||
}
|
||||
bios.data = intelImage.mid(bios.offset, bios.length);
|
||||
regions.push_back(bios);
|
||||
}
|
||||
else {
|
||||
msg(usprintf("%s: descriptor parsing failed, BIOS region not found in descriptor", __FUNCTION__));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
// Add all other regions
|
||||
for (UINT8 i = Subtypes::GbeRegion; i <= Subtypes::PttRegion; i++) {
|
||||
if (descriptorVersion == 1 && i == Subtypes::MicrocodeRegion)
|
||||
break; // Do not parse Microcode and other following regions for legacy descriptors
|
||||
|
||||
const UINT16* RegionBase = ((const UINT16*)regionSection) + 2 * i;
|
||||
const UINT16* RegionLimit = ((const UINT16*)regionSection) + 2 * i + 1;
|
||||
if (*RegionLimit && !(*RegionBase == 0xFFFF && *RegionLimit == 0xFFFF)) {
|
||||
REGION_INFO region;
|
||||
region.type = i;
|
||||
region.offset = calculateRegionOffset(*RegionBase);
|
||||
region.length = calculateRegionSize(*RegionBase, *RegionLimit);
|
||||
if (region.length != 0) {
|
||||
if ((UINT32)intelImage.size() < region.offset + region.length) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, region.type)
|
||||
+ UString(" region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image"),
|
||||
index);
|
||||
return U_TRUNCATED_IMAGE;
|
||||
}
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
regions.push_back(region);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Regions can not be empty here
|
||||
if (regions.empty()) {
|
||||
msg(usprintf("%s: descriptor parsing failed, no regions found", __FUNCTION__));
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
|
||||
// Sort regions in ascending order
|
||||
std::sort(regions.begin(), regions.end());
|
||||
|
||||
// Check for intersections and paddings between regions
|
||||
REGION_INFO region;
|
||||
// Check intersection with the descriptor
|
||||
if (regions.front().offset < FLASH_DESCRIPTOR_SIZE) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, regions.front().type)
|
||||
+ UString(" region has intersection with flash descriptor"),
|
||||
index);
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Check for padding between descriptor and the first region
|
||||
else if (regions.front().offset > FLASH_DESCRIPTOR_SIZE) {
|
||||
region.offset = FLASH_DESCRIPTOR_SIZE;
|
||||
region.length = regions.front().offset - FLASH_DESCRIPTOR_SIZE;
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
regions.insert(regions.begin(), region);
|
||||
}
|
||||
// Check for intersections/paddings between regions
|
||||
for (size_t i = 1; i < regions.size(); i++) {
|
||||
UINT32 previousRegionEnd = regions[i-1].offset + regions[i-1].length;
|
||||
// Check for intersection with previous region
|
||||
if (regions[i].offset < previousRegionEnd) {
|
||||
msg(usprintf("%s: ", __FUNCTION__)
|
||||
+ itemSubtypeToUString(Types::Region, regions[i].type)
|
||||
+ UString(" region has intersection with ") + itemSubtypeToUString(Types::Region, regions[i - 1].type)
|
||||
+ UString(" region"),
|
||||
index);
|
||||
return U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Check for padding between current and previous regions
|
||||
else if (regions[i].offset > previousRegionEnd) {
|
||||
region.offset = previousRegionEnd;
|
||||
region.length = regions[i].offset - previousRegionEnd;
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
std::vector<REGION_INFO>::iterator iter = regions.begin();
|
||||
std::advance(iter, i);
|
||||
regions.insert(iter, region);
|
||||
}
|
||||
}
|
||||
// Check for padding after the last region
|
||||
if ((UINT64)regions.back().offset + (UINT64)regions.back().length < (UINT64)intelImage.size()) {
|
||||
region.offset = regions.back().offset + regions.back().length;
|
||||
region.length = (UINT32)(intelImage.size() - region.offset);
|
||||
region.data = intelImage.mid(region.offset, region.length);
|
||||
region.type = getPaddingType(region.data);
|
||||
regions.push_back(region);
|
||||
}
|
||||
|
||||
// Region map is consistent
|
||||
|
||||
// Intel image
|
||||
UString name("Intel image");
|
||||
UString info = usprintf("Full size: %Xh (%u)\nFlash chips: %u\nRegions: %u\nMasters: %u\nPCH straps: %u\nPROC straps: %u",
|
||||
(UINT32)intelImage.size(), (UINT32)intelImage.size(),
|
||||
descriptorMap->NumberOfFlashChips + 1, //
|
||||
descriptorMap->NumberOfRegions + 1, // Zero-based numbers in storage
|
||||
descriptorMap->NumberOfMasters + 1, //
|
||||
descriptorMap->NumberOfPchStraps,
|
||||
descriptorMap->NumberOfProcStraps);
|
||||
|
||||
// Set image base
|
||||
imageBase = model->base(parent) + localOffset;
|
||||
|
||||
// Add Intel image tree item
|
||||
index = model->addItem(localOffset, Types::Image, Subtypes::IntelImage, name, UString(), info, UByteArray(), intelImage, UByteArray(), Fixed, parent);
|
||||
|
||||
// Descriptor
|
||||
// Get descriptor info
|
||||
UByteArray body = intelImage.left(FLASH_DESCRIPTOR_SIZE);
|
||||
name = UString("Descriptor region");
|
||||
info = usprintf("ReservedVector:\n%02X %02X %02X %02X %02X %02X %02X %02X\n"
|
||||
"%02X %02X %02X %02X %02X %02X %02X %02X\nFull size: %Xh (%u)",
|
||||
descriptor->ReservedVector[0], descriptor->ReservedVector[1], descriptor->ReservedVector[2], descriptor->ReservedVector[3],
|
||||
descriptor->ReservedVector[4], descriptor->ReservedVector[5], descriptor->ReservedVector[6], descriptor->ReservedVector[7],
|
||||
descriptor->ReservedVector[8], descriptor->ReservedVector[9], descriptor->ReservedVector[10], descriptor->ReservedVector[11],
|
||||
descriptor->ReservedVector[12], descriptor->ReservedVector[13], descriptor->ReservedVector[14], descriptor->ReservedVector[15],
|
||||
FLASH_DESCRIPTOR_SIZE, FLASH_DESCRIPTOR_SIZE);
|
||||
|
||||
// Add offsets of actual regions
|
||||
for (size_t i = 0; i < regions.size(); i++) {
|
||||
if (regions[i].type != Subtypes::ZeroPadding && regions[i].type != Subtypes::OnePadding && regions[i].type != Subtypes::DataPadding)
|
||||
info += "\n" + itemSubtypeToUString(Types::Region, regions[i].type)
|
||||
+ usprintf(" region offset: %Xh", regions[i].offset + localOffset);
|
||||
}
|
||||
|
||||
// Region access settings
|
||||
if (descriptorVersion == 1) {
|
||||
const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8((UINT8*)descriptor, descriptorMap->MasterBase);
|
||||
info += UString("\nRegion access settings:");
|
||||
info += usprintf("\nBIOS: %02Xh %02Xh ME: %02Xh %02Xh\nGbE: %02Xh %02Xh",
|
||||
masterSection->BiosRead,
|
||||
masterSection->BiosWrite,
|
||||
masterSection->MeRead,
|
||||
masterSection->MeWrite,
|
||||
masterSection->GbeRead,
|
||||
masterSection->GbeWrite);
|
||||
|
||||
// BIOS access table
|
||||
info += UString("\nBIOS access table:")
|
||||
+ UString("\n Read Write")
|
||||
+ usprintf("\nDesc %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ");
|
||||
info += UString("\nBIOS Yes Yes")
|
||||
+ usprintf("\nME %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ");
|
||||
info += usprintf("\nGbE %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ");
|
||||
info += usprintf("\nPDR %s %s", masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ");
|
||||
}
|
||||
else if (descriptorVersion == 2) {
|
||||
const FLASH_DESCRIPTOR_MASTER_SECTION_V2* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION_V2*)calculateAddress8((UINT8*)descriptor, descriptorMap->MasterBase);
|
||||
info += UString("\nRegion access settings:");
|
||||
info += usprintf("\nBIOS: %03Xh %03Xh ME: %03Xh %03Xh\nGbE: %03Xh %03Xh EC: %03Xh %03Xh",
|
||||
masterSection->BiosRead,
|
||||
masterSection->BiosWrite,
|
||||
masterSection->MeRead,
|
||||
masterSection->MeWrite,
|
||||
masterSection->GbeRead,
|
||||
masterSection->GbeWrite,
|
||||
masterSection->EcRead,
|
||||
masterSection->EcWrite);
|
||||
|
||||
// BIOS access table
|
||||
info += UString("\nBIOS access table:")
|
||||
+ UString("\n Read Write")
|
||||
+ usprintf("\nDesc %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ");
|
||||
info += UString("\nBIOS Yes Yes")
|
||||
+ usprintf("\nME %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ");
|
||||
info += usprintf("\nGbE %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ");
|
||||
info += usprintf("\nPDR %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ");
|
||||
info += usprintf("\nEC %s %s",
|
||||
masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ",
|
||||
masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ");
|
||||
|
||||
// Prepend descriptor version if present
|
||||
if (descriptorMap->DescriptorVersion != FLASH_DESCRIPTOR_VERSION_INVALID) {
|
||||
const FLASH_DESCRIPTOR_VERSION* version = (const FLASH_DESCRIPTOR_VERSION*)&descriptorMap->DescriptorVersion;
|
||||
UString versionStr = usprintf("Flash descriptor version: %d.%d", version->Major, version->Minor);
|
||||
if (version->Major != FLASH_DESCRIPTOR_VERSION_MAJOR || version->Minor != FLASH_DESCRIPTOR_VERSION_MINOR) {
|
||||
versionStr += ", unknown";
|
||||
msg(usprintf("%s: unknown flash descriptor version %d.%d", __FUNCTION__, version->Major, version->Minor));
|
||||
}
|
||||
info = versionStr + "\n" + info;
|
||||
}
|
||||
}
|
||||
|
||||
// VSCC table
|
||||
const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)((UINT8*)descriptor + ((UINT16)upperMap->VsccTableBase << 4));
|
||||
info += UString("\nFlash chips in VSCC table:");
|
||||
UINT8 vsscTableSize = upperMap->VsccTableSize * sizeof(UINT32) / sizeof(VSCC_TABLE_ENTRY);
|
||||
for (UINT8 i = 0; i < vsscTableSize; i++) {
|
||||
UString jedecId = jedecIdToUString(vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1);
|
||||
info += usprintf("\n%02X%02X%02X (", vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1)
|
||||
+ jedecId
|
||||
+ UString(")");
|
||||
if (jedecId.startsWith("Unknown")) {
|
||||
msg(usprintf("%s: SPI flash with unknown JEDEC ID %02X%02X%02X found in VSCC table", __FUNCTION__,
|
||||
vsccTableEntry->VendorId, vsccTableEntry->DeviceId0, vsccTableEntry->DeviceId1), index);
|
||||
}
|
||||
vsccTableEntry++;
|
||||
}
|
||||
|
||||
// Add descriptor tree item
|
||||
UModelIndex regionIndex = model->addItem(localOffset, Types::Region, Subtypes::DescriptorRegion, name, UString(), info, UByteArray(), body, UByteArray(), Fixed, index);
|
||||
|
||||
// Parse regions
|
||||
USTATUS result = U_SUCCESS;
|
||||
USTATUS parseResult = U_SUCCESS;
|
||||
for (size_t i = 0; i < regions.size(); i++) {
|
||||
region = regions[i];
|
||||
switch (region.type) {
|
||||
case Subtypes::BiosRegion:
|
||||
result = parseBiosRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::MeRegion:
|
||||
result = parseMeRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::GbeRegion:
|
||||
result = parseGbeRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::PdrRegion:
|
||||
result = parsePdrRegion(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::DevExp1Region:
|
||||
result = parseDevExp1Region(region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::Bios2Region:
|
||||
case Subtypes::MicrocodeRegion:
|
||||
case Subtypes::EcRegion:
|
||||
case Subtypes::DevExp2Region:
|
||||
case Subtypes::IeRegion:
|
||||
case Subtypes::Tgbe1Region:
|
||||
case Subtypes::Tgbe2Region:
|
||||
case Subtypes::Reserved1Region:
|
||||
case Subtypes::Reserved2Region:
|
||||
case Subtypes::PttRegion:
|
||||
result = parseGenericRegion(region.type, region.data, region.offset, index, regionIndex);
|
||||
break;
|
||||
case Subtypes::ZeroPadding:
|
||||
case Subtypes::OnePadding:
|
||||
case Subtypes::DataPadding: {
|
||||
// Add padding between regions
|
||||
UByteArray padding = intelImage.mid(region.offset, region.length);
|
||||
|
||||
// Get info
|
||||
name = UString("Padding");
|
||||
info = usprintf("Full size: %Xh (%u)",
|
||||
(UINT32)padding.size(), (UINT32)padding.size());
|
||||
|
||||
// Add tree item
|
||||
regionIndex = model->addItem(region.offset, Types::Padding, getPaddingType(padding), name, UString(), info, UByteArray(), padding, UByteArray(), Fixed, index);
|
||||
result = U_SUCCESS;
|
||||
} break;
|
||||
default:
|
||||
msg(usprintf("%s: region of unknown type found", __FUNCTION__), index);
|
||||
result = U_INVALID_FLASH_DESCRIPTOR;
|
||||
}
|
||||
// Store the first failed result as a final result
|
||||
if (!parseResult && result) {
|
||||
parseResult = result;
|
||||
}
|
||||
}
|
||||
|
||||
return parseResult;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parseGbeRegion(const UByteArray & gbe, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (gbe.isEmpty())
|
||||
return U_EMPTY_REGION;
|
||||
if ((UINT32)gbe.size() < GBE_VERSION_OFFSET + sizeof(GBE_VERSION))
|
||||
return U_INVALID_REGION;
|
||||
|
||||
// Get info
|
||||
UString name("GbE region");
|
||||
const GBE_MAC_ADDRESS* mac = (const GBE_MAC_ADDRESS*)gbe.constData();
|
||||
const GBE_VERSION* version = (const GBE_VERSION*)(gbe.constData() + GBE_VERSION_OFFSET);
|
||||
UString info = usprintf("Full size: %Xh (%u)\nMAC: %02X:%02X:%02X:%02X:%02X:%02X\nVersion: %u.%u",
|
||||
(UINT32)gbe.size(), (UINT32)gbe.size(),
|
||||
mac->vendor[0], mac->vendor[1], mac->vendor[2],
|
||||
mac->device[0], mac->device[1], mac->device[2],
|
||||
version->major,
|
||||
version->minor);
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Region, Subtypes::GbeRegion, name, UString(), info, UByteArray(), gbe, UByteArray(), Fixed, parent);
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parseMeRegion(const UByteArray & me, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (me.isEmpty())
|
||||
return U_EMPTY_REGION;
|
||||
|
||||
// Get info
|
||||
UString name("ME region");
|
||||
UString info = usprintf("Full size: %Xh (%u)", (UINT32)me.size(), (UINT32)me.size());
|
||||
|
||||
// Parse region
|
||||
bool versionFound = true;
|
||||
bool emptyRegion = false;
|
||||
// Check for empty region
|
||||
if (me.size() == me.count('\xFF') || me.size() == me.count('\x00')) {
|
||||
// Further parsing not needed
|
||||
emptyRegion = true;
|
||||
info += ("\nState: empty");
|
||||
}
|
||||
else {
|
||||
// Search for new signature
|
||||
UINT32 sig2Value = ME_VERSION_SIGNATURE2;
|
||||
UByteArray sig2((const char*)&sig2Value, sizeof(sig2Value));
|
||||
INT32 versionOffset = (INT32)me.indexOf(sig2);
|
||||
if (versionOffset < 0) { // New signature not found
|
||||
// Search for old signature
|
||||
UINT32 sigValue = ME_VERSION_SIGNATURE;
|
||||
UByteArray sig((const char*)&sigValue, sizeof(sigValue));
|
||||
versionOffset = (INT32)me.indexOf(sig);
|
||||
if (versionOffset < 0) {
|
||||
info += ("\nVersion: unknown");
|
||||
versionFound = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Check sanity
|
||||
if ((UINT32)me.size() < (UINT32)versionOffset + sizeof(ME_VERSION))
|
||||
return U_INVALID_REGION;
|
||||
|
||||
// Add version information
|
||||
if (versionFound) {
|
||||
const ME_VERSION* version = (const ME_VERSION*)(me.constData() + versionOffset);
|
||||
info += usprintf("\nVersion: %u.%u.%u.%u",
|
||||
version->Major,
|
||||
version->Minor,
|
||||
version->Bugfix,
|
||||
version->Build);
|
||||
}
|
||||
}
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Region, Subtypes::MeRegion, name, UString(), info, UByteArray(), me, UByteArray(), Fixed, parent);
|
||||
|
||||
// Show messages
|
||||
if (emptyRegion) {
|
||||
msg(usprintf("%s: ME region is empty", __FUNCTION__), index);
|
||||
}
|
||||
else if (!versionFound) {
|
||||
msg(usprintf("%s: ME version is unknown, it can be damaged", __FUNCTION__), index);
|
||||
}
|
||||
else {
|
||||
meParser->parseMeRegionBody(index);
|
||||
}
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parsePdrRegion(const UByteArray & pdr, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (pdr.isEmpty())
|
||||
return U_EMPTY_REGION;
|
||||
|
||||
// Get info
|
||||
UString name("PDR region");
|
||||
UString info = usprintf("Full size: %Xh (%u)", (UINT32)pdr.size(), (UINT32)pdr.size());
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Region, Subtypes::PdrRegion, name, UString(), info, UByteArray(), pdr, UByteArray(), Fixed, parent);
|
||||
|
||||
// Parse PDR region as BIOS space
|
||||
USTATUS result = parseRawArea(index);
|
||||
if (result && result != U_VOLUMES_NOT_FOUND && result != U_INVALID_VOLUME && result != U_STORES_NOT_FOUND)
|
||||
return result;
|
||||
|
||||
return U_SUCCESS;
|
||||
}
|
||||
|
||||
USTATUS FfsParser::parseDevExp1Region(const UByteArray & devExp1, const UINT32 localOffset, const UModelIndex & parent, UModelIndex & index)
|
||||
{
|
||||
// Check sanity
|
||||
if (devExp1.isEmpty())
|
||||
return U_EMPTY_REGION;
|
||||
|
||||
// Get info
|
||||
UString name("DevExp1 region");
|
||||
UString info = usprintf("Full size: %Xh (%u)", (UINT32)devExp1.size(), (UINT32)devExp1.size());
|
||||
|
||||
bool emptyRegion = false;
|
||||
// Check for empty region
|
||||
if (devExp1.size() == devExp1.count('\xFF') || devExp1.size() == devExp1.count('\x00')) {
|
||||
// Further parsing not needed
|
||||
emptyRegion = true;
|
||||
info += ("\nState: empty");
|
||||
}
|
||||
|
||||
// Add tree item
|
||||
index = model->addItem(localOffset, Types::Region, Subtypes::DevExp1Region, name, UString(), info, UByteArray(), devExp1, UByteArray(), Fixed, parent);
|
||||
|
||||
if (!emptyRegion) {
|
||||
meParser->parseMeRegionBody(index);
|
||||
}
|
||||
return U_SUCCESS;
|
||||
}
|
222
common/intel_descriptor.h
Normal file
222
common/intel_descriptor.h
Normal file
|
@ -0,0 +1,222 @@
|
|||
/* intel_descriptor.h
|
||||
|
||||
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,
|
||||
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
*/
|
||||
|
||||
#ifndef INTEL_DESCRIPTOR_H
|
||||
#define INTEL_DESCRIPTOR_H
|
||||
|
||||
#include "basetypes.h"
|
||||
#include "ustring.h"
|
||||
#include "ubytearray.h"
|
||||
|
||||
// Make sure we use right packing rules
|
||||
#pragma pack(push,1)
|
||||
|
||||
// Flash descriptor header
|
||||
typedef struct FLASH_DESCRIPTOR_HEADER_ {
|
||||
UINT8 ReservedVector[16]; // Reserved for ARM ResetVector, 0xFFs on x86/x86-64 machines
|
||||
UINT32 Signature; // 0x0FF0A55A
|
||||
} FLASH_DESCRIPTOR_HEADER;
|
||||
|
||||
// Flash descriptor signature
|
||||
#define FLASH_DESCRIPTOR_SIGNATURE 0x0FF0A55A
|
||||
|
||||
// Descriptor region size
|
||||
#define FLASH_DESCRIPTOR_SIZE 0x1000
|
||||
|
||||
// Maximum base value in descriptor map
|
||||
#define FLASH_DESCRIPTOR_MAX_BASE 0xE0
|
||||
|
||||
// Descriptor version was reserved in older firmware
|
||||
#define FLASH_DESCRIPTOR_VERSION_INVALID 0xFFFFFFFF
|
||||
// The only known version found in Coffee Lake
|
||||
#define FLASH_DESCRIPTOR_VERSION_MAJOR 1
|
||||
#define FLASH_DESCRIPTOR_VERSION_MINOR 0
|
||||
|
||||
// Descriptor version present in Coffee Lake and newer
|
||||
typedef struct _FLASH_DESCRIPTOR_VERSION {
|
||||
UINT32 Reserved : 14;
|
||||
UINT32 Minor : 7;
|
||||
UINT32 Major : 11;
|
||||
} FLASH_DESCRIPTOR_VERSION;
|
||||
|
||||
// Descriptor map
|
||||
// Base fields are storing bits [11:4] of actual base addresses, all other bits are 0
|
||||
typedef struct FLASH_DESCRIPTOR_MAP_ {
|
||||
// FLMAP0
|
||||
UINT32 ComponentBase : 8;
|
||||
UINT32 NumberOfFlashChips : 2; // Zero-based number of flash chips installed on board
|
||||
UINT32 : 6;
|
||||
UINT32 RegionBase : 8;
|
||||
UINT32 NumberOfRegions : 3; // Reserved in v2 descriptor
|
||||
UINT32 : 5;
|
||||
// FLMAP 1
|
||||
UINT32 MasterBase : 8;
|
||||
UINT32 NumberOfMasters : 2; // Zero-based number of flash masters
|
||||
UINT32 : 6;
|
||||
UINT32 PchStrapsBase : 8;
|
||||
UINT32 NumberOfPchStraps : 8; // One-based number of UINT32s to read as PCH straps, min=0, max=255 (1 Kb)
|
||||
// FLMAP 2
|
||||
UINT32 ProcStrapsBase : 8;
|
||||
UINT32 NumberOfProcStraps : 8; // One-based number of UINT32s to read as processor straps, min=0, max=255 (1 Kb)
|
||||
UINT32 : 16;
|
||||
// FLMAP 3
|
||||
UINT32 DescriptorVersion; // Reserved prior to Coffee Lake
|
||||
} FLASH_DESCRIPTOR_MAP;
|
||||
|
||||
// Component section
|
||||
// Flash parameters DWORD structure
|
||||
typedef struct FLASH_PARAMETERS_ {
|
||||
UINT8 FirstChipDensity : 4;
|
||||
UINT8 SecondChipDensity : 4;
|
||||
UINT8 : 8;
|
||||
UINT8 : 1;
|
||||
UINT8 ReadClockFrequency : 3; // Hardcoded value of 20 Mhz (000b) in v1 descriptors
|
||||
UINT8 FastReadEnabled : 1;
|
||||
UINT8 FastReadFrequency : 3;
|
||||
UINT8 FlashWriteFrequency : 3;
|
||||
UINT8 FlashReadStatusFrequency : 3;
|
||||
UINT8 DualOutputFastReadSupported : 1;
|
||||
UINT8 : 1;
|
||||
} FLASH_PARAMETERS;
|
||||
|
||||
// Flash densities
|
||||
#define FLASH_DENSITY_512KB 0x00
|
||||
#define FLASH_DENSITY_1MB 0x01
|
||||
#define FLASH_DENSITY_2MB 0x02
|
||||
#define FLASH_DENSITY_4MB 0x03
|
||||
#define FLASH_DENSITY_8MB 0x04
|
||||
#define FLASH_DENSITY_16MB 0x05
|
||||
#define FLASH_DENSITY_32MB 0x06
|
||||
#define FLASH_DENSITY_64MB 0x07
|
||||
#define FLASH_DENSITY_UNUSED 0x0F
|
||||
|
||||
// Flash frequencies
|
||||
#define FLASH_FREQUENCY_20MHZ 0x00
|
||||
#define FLASH_FREQUENCY_33MHZ 0x01
|
||||
#define FLASH_FREQUENCY_48MHZ 0x02
|
||||
#define FLASH_FREQUENCY_50MHZ_30MHZ 0x04
|
||||
#define FLASH_FREQUENCY_17MHZ 0x06
|
||||
|
||||
// Component section structure
|
||||
typedef struct FLASH_DESCRIPTOR_COMPONENT_SECTION_ {
|
||||
FLASH_PARAMETERS FlashParameters;
|
||||
UINT8 InvalidInstruction0; // Instructions for SPI chip, that must not be executed, like FLASH ERASE
|
||||
UINT8 InvalidInstruction1; //
|
||||
UINT8 InvalidInstruction2; //
|
||||
UINT8 InvalidInstruction3; //
|
||||
UINT16 PartitionBoundary; // Upper 16 bit of partition boundary address. Default is 0x0000, which makes the boundary to be 0x00001000
|
||||
UINT16 : 16;
|
||||
} FLASH_DESCRIPTOR_COMPONENT_SECTION;
|
||||
|
||||
// Region section
|
||||
// All base and limit register are storing upper part of actual UINT32 base and limit
|
||||
// If limit is zero - region is not present
|
||||
typedef struct FLASH_DESCRIPTOR_REGION_SECTION_ {
|
||||
UINT16 DescriptorBase; // Descriptor
|
||||
UINT16 DescriptorLimit; //
|
||||
UINT16 BiosBase; // BIOS
|
||||
UINT16 BiosLimit; //
|
||||
UINT16 MeBase; // Management Engine
|
||||
UINT16 MeLimit; //
|
||||
UINT16 GbeBase; // Gigabit Ethernet
|
||||
UINT16 GbeLimit; //
|
||||
UINT16 PdrBase; // Platform Data
|
||||
UINT16 PdrLimit; //
|
||||
UINT16 DevExp1Base; // Device Expansion 1
|
||||
UINT16 DevExp1Limit; //
|
||||
UINT16 Bios2Base; // Secondary BIOS
|
||||
UINT16 Bios2Limit; //
|
||||
UINT16 MicrocodeBase; // CPU microcode
|
||||
UINT16 MicrocodeLimit; //
|
||||
UINT16 EcBase; // Embedded Controller
|
||||
UINT16 EcLimit; //
|
||||
UINT16 DevExp2Base; // Device Expansion 2
|
||||
UINT16 DevExp2Limit; //
|
||||
UINT16 IeBase; // Innovation Engine
|
||||
UINT16 IeLimit; //
|
||||
UINT16 Tgbe1Base; // 10 Gigabit Ethernet 1
|
||||
UINT16 Tgbe1Limit; //
|
||||
UINT16 Tgbe2Base; // 10 Gigabit Ethernet 2
|
||||
UINT16 Tgbe2Limit; //
|
||||
UINT16 Reserved1Base; // Reserved 1
|
||||
UINT16 Reserved1Limit; //
|
||||
UINT16 Reserved2Base; // Reserved 2
|
||||
UINT16 Reserved2Limit; //
|
||||
UINT16 PttBase; // Platform Trust Technology
|
||||
UINT16 PttLimit; //
|
||||
} FLASH_DESCRIPTOR_REGION_SECTION;
|
||||
|
||||
// Master section
|
||||
typedef struct FLASH_DESCRIPTOR_MASTER_SECTION_ {
|
||||
UINT16 BiosId;
|
||||
UINT8 BiosRead;
|
||||
UINT8 BiosWrite;
|
||||
UINT16 MeId;
|
||||
UINT8 MeRead;
|
||||
UINT8 MeWrite;
|
||||
UINT16 GbeId;
|
||||
UINT8 GbeRead;
|
||||
UINT8 GbeWrite;
|
||||
} FLASH_DESCRIPTOR_MASTER_SECTION;
|
||||
|
||||
// Master section v2 (Skylake+)
|
||||
typedef struct FLASH_DESCRIPTOR_MASTER_SECTION_V2_ {
|
||||
UINT32 : 8;
|
||||
UINT32 BiosRead : 12;
|
||||
UINT32 BiosWrite : 12;
|
||||
UINT32 : 8;
|
||||
UINT32 MeRead : 12;
|
||||
UINT32 MeWrite : 12;
|
||||
UINT32 : 8;
|
||||
UINT32 GbeRead : 12;
|
||||
UINT32 GbeWrite : 12;
|
||||
UINT32 : 32;
|
||||
UINT32 : 8;
|
||||
UINT32 EcRead : 12;
|
||||
UINT32 EcWrite : 12;
|
||||
} FLASH_DESCRIPTOR_MASTER_SECTION_V2;
|
||||
|
||||
// Region access bits in master section
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_DESC 0x01
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_BIOS 0x02
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_ME 0x04
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_GBE 0x08
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_PDR 0x10
|
||||
#define FLASH_DESCRIPTOR_REGION_ACCESS_EC 0x20
|
||||
|
||||
// Base address of descriptor upper map
|
||||
#define FLASH_DESCRIPTOR_UPPER_MAP_BASE 0x0EFC
|
||||
|
||||
// Descriptor upper map structure
|
||||
typedef struct FLASH_DESCRIPTOR_UPPER_MAP_ {
|
||||
UINT8 VsccTableBase; // Base address of VSCC Table for ME, bits [11:4]
|
||||
UINT8 VsccTableSize; // Counted in UINT32s
|
||||
UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen
|
||||
} FLASH_DESCRIPTOR_UPPER_MAP;
|
||||
|
||||
// VSCC table entry structure
|
||||
typedef struct VSCC_TABLE_ENTRY_ {
|
||||
UINT8 VendorId; // JEDEC VendorID byte
|
||||
UINT8 DeviceId0; // JEDEC DeviceID first byte
|
||||
UINT8 DeviceId1; // JEDEC DeviceID second byte
|
||||
UINT8 ReservedZero; // Reserved, must be zero
|
||||
UINT32 VsccRegisterValue; // VSCC register value
|
||||
} VSCC_TABLE_ENTRY;
|
||||
|
||||
// Base address and size of OEM section
|
||||
#define FLASH_DESCRIPTOR_OEM_SECTION_BASE 0x0F00
|
||||
#define FLASH_DESCRIPTOR_OEM_SECTION_SIZE 0x100
|
||||
|
||||
// Restore previous packing rules
|
||||
#pragma pack(pop)
|
||||
|
||||
#endif // INTEL_DESCRIPTOR_H
|
|
@ -26,6 +26,7 @@ uefitoolcommon = static_library('uefitoolcommon',
|
|||
'meparser.cpp',
|
||||
'fitparser.cpp',
|
||||
'ffsparser.cpp',
|
||||
'ffsparser_intel.cpp',
|
||||
'ffsreport.cpp',
|
||||
'peimage.cpp',
|
||||
'treeitem.cpp',
|
||||
|
|
|
@ -19,6 +19,7 @@ SET(PROJECT_SOURCES
|
|||
../common/nvramparser.cpp
|
||||
../common/meparser.cpp
|
||||
../common/ffsparser.cpp
|
||||
../common/ffsparser_intel.cpp
|
||||
../common/fitparser.cpp
|
||||
../common/peimage.cpp
|
||||
../common/treeitem.cpp
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue