Port of latest descriptor handling changes from master

- added Skylake+ descriptor format support
This commit is contained in:
Nikolaj Schlej 2015-09-12 22:53:07 +02:00
parent d36951da88
commit b8317ac4f2
4 changed files with 240 additions and 92 deletions

View File

@ -17,7 +17,7 @@
UEFITool::UEFITool(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::UEFITool),
version(tr("0.30.0_alpha8"))
version(tr("0.30.0_alpha9"))
{
clipboard = QApplication::clipboard();

View File

@ -34,37 +34,39 @@ typedef struct _FLASH_DESCRIPTOR_HEADER {
// Descriptor map
// Base fields are storing bits [11:4] of actual base addresses, all other bits are 0
typedef struct _FLASH_DESCRIPTOR_MAP {
UINT8 ComponentBase; // 0x03 on most machines
UINT8 NumberOfFlashChips; // Zero-based number of flash chips installed on board
UINT8 RegionBase; // 0x04 on most machines
UINT8 NumberOfRegions; // Zero-based number of flash regions (descriptor is always included)
UINT8 MasterBase; // 0x06 on most machines
UINT8 NumberOfMasters; // Zero-based number of flash masters
UINT8 PchStrapsBase; // 0x10 on most machines
UINT8 NumberOfPchStraps; // One-based number of UINT32s to read as PCH Straps, min=0, max=255 (1 Kb)
UINT8 ProcStrapsBase; // 0x20 on most machines
UINT8 NumberOfProcStraps; // Number of PROC straps to be read, can be 0 or 1
UINT8 IccTableBase; // 0x21 on most machines
UINT8 NumberOfIccTableEntries; // 0x00 on most machines
UINT8 DmiTableBase; // 0x25 on most machines
UINT8 NumberOfDmiTableEntries; // 0x00 on most machines
UINT16 ReservedZero; // Still unknown, zeros in all descriptors I have seen
// 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;
} FLASH_DESCRIPTOR_MAP;
// Component section
// Flash parameters DWORD structure
typedef struct _FLASH_PARAMETERS {
UINT8 FirstChipDensity : 3;
UINT8 SecondChipDensity : 3;
UINT8 ReservedZero0 : 2; // Still unknown, zeros in all descriptors I have seen
UINT8 ReservedZero1 : 8; // Still unknown, zeros in all descriptors I have seen
UINT8 ReservedZero2 : 4; // Still unknown, zeros in all descriptors I have seen
UINT8 FirstChipDensity : 4;
UINT8 SecondChipDensity : 4;
UINT8 : 8;
UINT8 : 1;
UINT8 ReadClockFrequency : 3; // Hardcoded value of 20 Mhz (000b) in v1 descriptors and 17 Mhz (110b) in v2 ones
UINT8 FastReadEnabled : 1;
UINT8 FastReadFreqency : 3;
UINT8 FlashReadStatusFrequency : 3;
UINT8 FastReadFrequency : 3;
UINT8 FlashWriteFrequency : 3;
UINT8 FlashReadStatusFrequency : 3;
UINT8 DualOutputFastReadSupported : 1;
UINT8 ReservedZero3 : 1; // Still unknown, zero in all descriptors I have seen
UINT8 : 1;
} FLASH_PARAMETERS;
// Flash densities
@ -74,11 +76,16 @@ typedef struct _FLASH_PARAMETERS {
#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_50MHZ 0x04
#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 {
@ -95,23 +102,28 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_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 ReservedZero; // Still unknown, zero in all descriptors I have seen
UINT16 FlashBlockEraseSize; // Size of block erased by single BLOCK ERASE command
UINT16 BiosBase;
UINT16 BiosLimit;
UINT16 MeBase;
UINT16 MeLimit;
UINT16 GbeBase;
UINT16 GbeLimit;
UINT16 PdrBase;
UINT16 PdrLimit;
UINT16 DescriptorBase; // Descriptor
UINT16 DescriptorLimit; //
UINT16 BiosBase; // BIOS
UINT16 BiosLimit; //
UINT16 MeBase; // ME
UINT16 MeLimit; //
UINT16 GbeBase; // GbE
UINT16 GbeLimit; //
UINT16 PdrBase; // PDR
UINT16 PdrLimit; //
UINT16 Region5Base; // Reserved region
UINT16 Region5Limit; //
UINT16 Region6Base; // Reserved region
UINT16 Region6Limit; //
UINT16 Region7Base; // Reserved region
UINT16 Region7Limit; //
UINT16 EcBase; // EC
UINT16 EcLimit; //
UINT16 Region9Base; // Reserved region
UINT16 Region9Limit; //
} FLASH_DESCRIPTOR_REGION_SECTION;
// Flash block erase sizes
#define FLASH_BLOCK_ERASE_SIZE_4KB 0x0000
#define FLASH_BLOCK_ERASE_SIZE_8KB 0x0001
#define FLASH_BLOCK_ERASE_SIZE_64KB 0x000F
// Master section
typedef struct _FLASH_DESCRIPTOR_MASTER_SECTION {
UINT16 BiosId;
@ -125,14 +137,30 @@ typedef struct _FLASH_DESCRIPTOR_MASTER_SECTION {
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
//!TODO: Describe PCH and PROC straps sections, as well as ICC and DMI tables
#define FLASH_DESCRIPTOR_REGION_ACCESS_EC 0x20
// Base address of descriptor upper map
#define FLASH_DESCRIPTOR_UPPER_MAP_BASE 0x0EFC
@ -155,7 +183,7 @@ typedef struct _VSCC_TABLE_ENTRY {
// Base address and size of OEM section
#define FLASH_DESCRIPTOR_OEM_SECTION_BASE 0x0F00
#define FLASH_DESCRIPTOR_OEM_SECTION_SIZE 0xFF
#define FLASH_DESCRIPTOR_OEM_SECTION_SIZE 0x100
// Restore previous packing rules
#pragma pack(pop)

View File

@ -216,18 +216,19 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER));
const FLASH_DESCRIPTOR_UPPER_MAP* upperMap = (const FLASH_DESCRIPTOR_UPPER_MAP*)(descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE);
const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8(descriptor, descriptorMap->RegionBase);
const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8(descriptor, descriptorMap->MasterBase);
const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8(descriptor, descriptorMap->ComponentBase);
// GbE region
QByteArray gbe;
UINT32 gbeBegin = 0;
UINT32 gbeEnd = 0;
if (regionSection->GbeLimit) {
gbeBegin = calculateRegionOffset(regionSection->GbeBase);
gbeEnd = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit);
gbe = intelImage.mid(gbeBegin, gbeEnd);
gbeEnd += gbeBegin;
// Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency
UINT8 descriptorVersion = 0;
if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_20MHZ) // Old descriptor
descriptorVersion = 1;
else if (componentSection->FlashParameters.ReadClockFrequency == FLASH_FREQUENCY_17MHZ) // Skylake+ descriptor
descriptorVersion = 2;
else {
msg(tr("parseIntelImage: unknown descriptor version with ReadClockFrequency %1h").hexarg(componentSection->FlashParameters.ReadClockFrequency));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// ME region
QByteArray me;
UINT32 meBegin = 0;
@ -238,16 +239,7 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
me = intelImage.mid(meBegin, meEnd);
meEnd += meBegin;
}
// PDR region
QByteArray pdr;
UINT32 pdrBegin = 0;
UINT32 pdrEnd = 0;
if (regionSection->PdrLimit) {
pdrBegin = calculateRegionOffset(regionSection->PdrBase);
pdrEnd = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit);
pdr = intelImage.mid(pdrBegin, pdrEnd);
pdrEnd += pdrBegin;
}
// BIOS region
QByteArray bios;
UINT32 biosBegin = 0;
@ -273,7 +265,43 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// GbE region
QByteArray gbe;
UINT32 gbeBegin = 0;
UINT32 gbeEnd = 0;
if (regionSection->GbeLimit) {
gbeBegin = calculateRegionOffset(regionSection->GbeBase);
gbeEnd = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit);
gbe = intelImage.mid(gbeBegin, gbeEnd);
gbeEnd += gbeBegin;
}
// PDR region
QByteArray pdr;
UINT32 pdrBegin = 0;
UINT32 pdrEnd = 0;
if (regionSection->PdrLimit) {
pdrBegin = calculateRegionOffset(regionSection->PdrBase);
pdrEnd = calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit);
pdr = intelImage.mid(pdrBegin, pdrEnd);
pdrEnd += pdrBegin;
}
// EC region
QByteArray ec;
UINT32 ecBegin = 0;
UINT32 ecEnd = 0;
if (descriptorVersion == 2) {
if (regionSection->EcLimit) {
pdrBegin = calculateRegionOffset(regionSection->EcBase);
pdrEnd = calculateRegionSize(regionSection->EcBase, regionSection->EcLimit);
pdr = intelImage.mid(ecBegin, ecEnd);
ecEnd += ecBegin;
}
}
// Check for intersections between regions
// Descriptor
if (hasIntersection(descriptorBegin, descriptorEnd, gbeBegin, gbeEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with GbE region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
@ -290,6 +318,11 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (descriptorVersion == 2 && hasIntersection(descriptorBegin, descriptorEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// GbE
if (hasIntersection(gbeBegin, gbeEnd, meBegin, meEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with ME region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
@ -302,6 +335,11 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (descriptorVersion == 2 && hasIntersection(gbeBegin, gbeEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// ME
if (hasIntersection(meBegin, meEnd, biosBegin, biosEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with BIOS region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
@ -310,23 +348,36 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (descriptorVersion == 2 && hasIntersection(meBegin, meEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// BIOS
if (hasIntersection(biosBegin, biosEnd, pdrBegin, pdrEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
if (descriptorVersion == 2 && hasIntersection(biosBegin, biosEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// PDR
if (descriptorVersion == 2 && hasIntersection(pdrBegin, pdrEnd, ecBegin, ecEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, PDR region has intersection with EC region"));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
// Region map is consistent
// Intel image
QString name = tr("Intel image");
QString info = tr("Full size: %1h (%2)\nFlash chips: %3\nRegions: %4\nMasters: %5\nPCH straps: %6\nPROC straps: %7\nICC table entries: %8")
QString info = tr("Full size: %1h (%2)\nFlash chips: %3\nRegions: %4\nMasters: %5\nPCH straps: %6\nPROC straps: %7")
.hexarg(intelImage.size()).arg(intelImage.size())
.arg(descriptorMap->NumberOfFlashChips + 1) //
.arg(descriptorMap->NumberOfRegions + 1) // Zero-based numbers in storage
.arg(descriptorMap->NumberOfMasters + 1) //
.arg(descriptorMap->NumberOfPchStraps)
.arg(descriptorMap->NumberOfProcStraps)
.arg(descriptorMap->NumberOfIccTableEntries);
.arg(descriptorMap->NumberOfProcStraps);
// Construct parsing data
pdata.fixed = TRUE;
@ -363,8 +414,10 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
}
// Region access settings
if (descriptorVersion == 1) {
const FLASH_DESCRIPTOR_MASTER_SECTION* masterSection = (const FLASH_DESCRIPTOR_MASTER_SECTION*)calculateAddress8(descriptor, descriptorMap->MasterBase);
info += tr("\nRegion access settings:");
info += tr("\nBIOS:%1%2h ME:%3%4h GbE:%5%6h")
info += tr("\nBIOS:%1h %2h ME:%3h %4h GbE:%5h %6h")
.hexarg2(masterSection->BiosRead, 2)
.hexarg2(masterSection->BiosWrite, 2)
.hexarg2(masterSection->MeRead, 2)
@ -388,6 +441,40 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
info += tr("\nPDR %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ")
.arg(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(descriptor, descriptorMap->MasterBase);
info += tr("\nRegion access settings:");
info += tr("\nBIOS: %1h %2h ME: %3h %4h\nGbE: %5h %6h EC: %7h %8h")
.hexarg2(masterSection->BiosRead, 3)
.hexarg2(masterSection->BiosWrite, 3)
.hexarg2(masterSection->MeRead, 3)
.hexarg2(masterSection->MeWrite, 3)
.hexarg2(masterSection->GbeRead, 3)
.hexarg2(masterSection->GbeWrite, 3)
.hexarg2(masterSection->EcRead, 3)
.hexarg2(masterSection->EcWrite, 3);
// BIOS access table
info += tr("\nBIOS access table:");
info += tr("\n Read Write");
info += tr("\nDesc %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? "Yes " : "No ");
info += tr("\nBIOS Yes Yes");
info += tr("\nME %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? "Yes " : "No ");
info += tr("\nGbE %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? "Yes " : "No ");
info += tr("\nPDR %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ");
info += tr("\nEC %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ")
.arg(masterSection->BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? "Yes " : "No ");
}
// VSCC table
const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)(descriptor + ((UINT16)upperMap->VsccTableBase << 4));
@ -430,6 +517,11 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
QModelIndex pdrIndex;
result = parsePdrRegion(pdr, pdrBegin, index, pdrIndex);
}
// Parse EC region
else if (descriptorVersion == 2 && offsets.at(i) == ecBegin) {
QModelIndex ecIndex;
result = parseEcRegion(ec, ecBegin, index, ecIndex);
}
if (result)
return result;
}
@ -445,6 +537,8 @@ STATUS FfsParser::parseIntelImage(const QByteArray & intelImage, const UINT32 pa
IntelDataEnd = biosEnd;
else if (LastRegionOffset == pdrBegin)
IntelDataEnd = pdrEnd;
else if (descriptorVersion == 2 && LastRegionOffset == ecBegin)
IntelDataEnd = ecEnd;
if (IntelDataEnd > (UINT32)intelImage.size()) { // Image file is truncated
msg(tr("parseIntelImage: image size %1 (%2) is smaller than the end of last region %3 (%4), may be damaged")
@ -613,6 +707,31 @@ STATUS FfsParser::parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffs
return ERR_SUCCESS;
}
STATUS FfsParser::parseEcRegion(const QByteArray & ec, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{
// Check sanity
if (ec.isEmpty())
return ERR_EMPTY_REGION;
// Get parent's parsing data
PARSING_DATA pdata = parsingDataFromQModelIndex(parent);
// Get info
QString name = tr("EC region");
QString info = tr("Full size: %1h (%2)").
hexarg(ec.size()).arg(ec.size());
// Construct parsing data
pdata.fixed = TRUE;
pdata.offset += parentOffset;
if (pdata.isOnFlash) info.prepend(tr("Offset: %1h\n").hexarg(pdata.offset));
// Add tree item
index = model->addItem(Types::Region, Subtypes::PdrRegion, name, QString(), info, QByteArray(), ec, parsingDataToQByteArray(pdata), parent);
return ERR_SUCCESS;
}
STATUS FfsParser::parseBiosRegion(const QByteArray & bios, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index)
{
// Sanity check

View File

@ -66,6 +66,7 @@ private:
STATUS parseMeRegion(const QByteArray & me, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseBiosRegion(const QByteArray & bios, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parsePdrRegion(const QByteArray & pdr, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parseEcRegion(const QByteArray & ec, const UINT32 parentOffset, const QModelIndex & parent, QModelIndex & index);
STATUS parsePadFileBody(const QModelIndex & index);
STATUS parseSections(QByteArray sections, const QModelIndex & index);