UT 0.21.0

- added support for new Intel descriptor type, based on
[this](http://review.coreboot.org/gitweb?p=coreboot.git;a=commit;h=1f7fd720c81755144423f2d4062c39cc651adc0a)
coreboot commit, thanks to lordkag for issue #32
- solved a bug with incorrect volume free space item placement during
volume replace, now works as expected
- solved an issue with incorrect Aptio capsule parsing introduced in
0.20.8
This commit is contained in:
Nikolaj Schlej 2015-09-06 23:46:26 +02:00
parent 9c4ddbec62
commit aa80837bf5
7 changed files with 309 additions and 126 deletions

View file

@ -34,37 +34,38 @@ typedef struct _FLASH_DESCRIPTOR_HEADER {
// Descriptor map // Descriptor map
// Base fields are storing bits [11:4] of actual base addresses, all other bits are 0 // Base fields are storing bits [11:4] of actual base addresses, all other bits are 0
typedef struct _FLASH_DESCRIPTOR_MAP { typedef struct _FLASH_DESCRIPTOR_MAP {
UINT8 ComponentBase; // 0x03 on most machines // FLMAP0
UINT8 NumberOfFlashChips; // Zero-based number of flash chips installed on board UINT32 ComponentBase : 8;
UINT8 RegionBase; // 0x04 on most machines UINT32 NumberOfFlashChips : 2; // Zero-based number of flash chips installed on board
UINT8 NumberOfRegions; // Zero-based number of flash regions (descriptor is always included) UINT32 : 6;
UINT8 MasterBase; // 0x06 on most machines UINT32 RegionBase : 8;
UINT8 NumberOfMasters; // Zero-based number of flash masters UINT32 : 8;
UINT8 PchStrapsBase; // 0x10 on most machines // FLMAP 1
UINT8 NumberOfPchStraps; // One-based number of UINT32s to read as PCH Straps, min=0, max=255 (1 Kb) UINT32 MasterBase : 8;
UINT8 ProcStrapsBase; // 0x20 on most machines UINT32 NumberOfMasters : 2;
UINT8 NumberOfProcStraps; // Number of PROC straps to be read, can be 0 or 1 UINT32 : 6;
UINT8 IccTableBase; // 0x21 on most machines UINT32 PchStrapsBase : 8;
UINT8 NumberOfIccTableEntries; // 0x00 on most machines UINT32 NumberOfPchStraps : 8; // One-based number of UINT32s to read as PCH straps, min=0, max=255 (1 Kb)
UINT8 DmiTableBase; // 0x25 on most machines // FLMAP 2
UINT8 NumberOfDmiTableEntries; // 0x00 on most machines UINT32 ProcStrapsBase : 8;
UINT16 ReservedZero; // Still unknown, zeros in all descriptors I have seen UINT32 NumberOfProcStraps : 8; // One-based number of UINT32s to read as processor straps, min=0, max=255 (1 Kb)
UINT32: 16;
} FLASH_DESCRIPTOR_MAP; } FLASH_DESCRIPTOR_MAP;
// Component section // Component section
// Flash parameters DWORD structure // Flash parameters DWORD structure
typedef struct _FLASH_PARAMETERS { typedef struct _FLASH_PARAMETERS {
UINT8 FirstChipDensity : 3; UINT8 FirstChipDensity : 4;
UINT8 SecondChipDensity : 3; UINT8 SecondChipDensity : 4;
UINT8 ReservedZero0 : 2; // Still unknown, zeros in all descriptors I have seen UINT8 : 8;
UINT8 ReservedZero1 : 8; // Still unknown, zeros in all descriptors I have seen UINT8 : 1;
UINT8 ReservedZero2 : 4; // Still unknown, zeros in all descriptors I have seen UINT8 ReadClockFreqency : 3; // Hardcoded value of 20 Mhz (000b) in v1 descriptors and 17 Mhz (110b) in v2 ones
UINT8 FastReadEnabled : 1; UINT8 FastReadEnabled : 1;
UINT8 FastReadFreqency : 3; UINT8 FastReadFreqency : 3;
UINT8 FlashReadStatusFrequency : 3; UINT8 FlashReadStatusFrequency : 3;
UINT8 FlashWriteFrequency : 3; UINT8 FlashWriteFrequency : 3;
UINT8 DualOutputFastReadSupported : 1; UINT8 DualOutputFastReadSupported : 1;
UINT8 ReservedZero3 : 1; // Still unknown, zero in all descriptors I have seen UINT8 : 1;
} FLASH_PARAMETERS; } FLASH_PARAMETERS;
// Flash densities // Flash densities
@ -74,11 +75,16 @@ typedef struct _FLASH_PARAMETERS {
#define FLASH_DENSITY_4MB 0x03 #define FLASH_DENSITY_4MB 0x03
#define FLASH_DENSITY_8MB 0x04 #define FLASH_DENSITY_8MB 0x04
#define FLASH_DENSITY_16MB 0x05 #define FLASH_DENSITY_16MB 0x05
#define FLASH_DENSITY_32MB 0x06
#define FLASH_DENSITY_64MB 0x07
#define FLASH_DENSITY_UNUSED 0x0F
// Flash frequencies // Flash frequencies
#define FLASH_FREQUENCY_20MHZ 0x00 #define FLASH_FREQUENCY_20MHZ 0x00
#define FLASH_FREQUENCY_33MHZ 0x01 #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 // Component section structure
typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION { typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION {
@ -87,24 +93,45 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION {
UINT8 InvalidInstruction1; // UINT8 InvalidInstruction1; //
UINT8 InvalidInstruction2; // UINT8 InvalidInstruction2; //
UINT8 InvalidInstruction3; // UINT8 InvalidInstruction3; //
UINT16 PartitionBoundary; // Upper 16 bit of partition boundary address. Default is 0x0000, which makes the boundary to be 0x00001000
UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen
} FLASH_DESCRIPTOR_COMPONENT_SECTION; } FLASH_DESCRIPTOR_COMPONENT_SECTION;
// Component section structure
typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION_V2 {
FLASH_PARAMETERS FlashParameters;
UINT8 InvalidInstruction0; // Instructions for SPI chip, that must not be executed, like FLASH ERASE
UINT8 InvalidInstruction1; //
UINT8 InvalidInstruction2; //
UINT8 InvalidInstruction3; //
UINT8 InvalidInstruction4; //
UINT8 InvalidInstruction5; //
UINT8 InvalidInstruction6; //
UINT8 InvalidInstruction7; //
} FLASH_DESCRIPTOR_COMPONENT_SECTION_V2;
// Region section // Region section
// All base and limit register are storing upper part of actual UINT32 base and limit // All base and limit register are storing upper part of actual UINT32 base and limit
// If limit is zero - region is not present // If limit is zero - region is not present
typedef struct _FLASH_DESCRIPTOR_REGION_SECTION { typedef struct _FLASH_DESCRIPTOR_REGION_SECTION {
UINT16 ReservedZero; // Still unknown, zero in all descriptors I have seen UINT16 :16;
UINT16 FlashBlockEraseSize; // Size of block erased by single BLOCK ERASE command UINT16 FlashBlockEraseSize; // Size of block erased by single BLOCK ERASE command
UINT16 BiosBase; UINT16 Region0Base; // BIOS
UINT16 BiosLimit; UINT16 Region0Limit; //
UINT16 MeBase; UINT16 Region1Base; // ME
UINT16 MeLimit; UINT16 Region1Limit; //
UINT16 GbeBase; UINT16 Region2Base; // GbE
UINT16 GbeLimit; UINT16 Region2Limit; //
UINT16 PdrBase; UINT16 Region3Base; // PDR
UINT16 PdrLimit; UINT16 Region3Limit; //
UINT16 Region4Base; // Reserved region
UINT16 Region4Limit; //
UINT16 Region5Base; // Reserved region
UINT16 Region5Limit; //
UINT16 Region6Base; // Reserved region
UINT16 Region6Limit; //
UINT16 Region7Base; // Reserved region
UINT16 Region7Limit; //
UINT16 Region8Base; // EC
UINT16 Region8Limit; //
} FLASH_DESCRIPTOR_REGION_SECTION; } FLASH_DESCRIPTOR_REGION_SECTION;
// Flash block erase sizes // Flash block erase sizes
@ -125,14 +152,30 @@ typedef struct _FLASH_DESCRIPTOR_MASTER_SECTION {
UINT8 GbeWrite; UINT8 GbeWrite;
} FLASH_DESCRIPTOR_MASTER_SECTION; } 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 // Region access bits in master section
#define FLASH_DESCRIPTOR_REGION_ACCESS_DESC 0x01 #define FLASH_DESCRIPTOR_REGION_ACCESS_DESC 0x01
#define FLASH_DESCRIPTOR_REGION_ACCESS_BIOS 0x02 #define FLASH_DESCRIPTOR_REGION_ACCESS_BIOS 0x02
#define FLASH_DESCRIPTOR_REGION_ACCESS_ME 0x04 #define FLASH_DESCRIPTOR_REGION_ACCESS_ME 0x04
#define FLASH_DESCRIPTOR_REGION_ACCESS_GBE 0x08 #define FLASH_DESCRIPTOR_REGION_ACCESS_GBE 0x08
#define FLASH_DESCRIPTOR_REGION_ACCESS_PDR 0x10 #define FLASH_DESCRIPTOR_REGION_ACCESS_PDR 0x10
#define FLASH_DESCRIPTOR_REGION_ACCESS_EC 0x20
//!TODO: Describe PCH and PROC straps sections, as well as ICC and DMI tables
// Base address of descriptor upper map // Base address of descriptor upper map
#define FLASH_DESCRIPTOR_UPPER_MAP_BASE 0x0EFC #define FLASH_DESCRIPTOR_UPPER_MAP_BASE 0x0EFC

4
ffs.h
View file

@ -53,10 +53,6 @@ const QByteArray EFI_CAPSULE_GUID
const QByteArray INTEL_CAPSULE_GUID const QByteArray INTEL_CAPSULE_GUID
("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16); ("\xB9\x82\x91\x53\xB5\xAB\x91\x43\xB6\x9A\xE3\xA9\x43\xF7\x2F\xCC", 16);
// Lenovo capsule GUID
const QByteArray LENOVO_CAPSULE_GUID
("\x8B\xA6\x3C\x4A\x23\x77\xFB\x48\x80\x3D\x57\x8C\xC1\xFE\xC4\x4D", 16);
// Toshiba EFI Capsule header // Toshiba EFI Capsule header
typedef struct _TOSHIBA_CAPSULE_HEADER { typedef struct _TOSHIBA_CAPSULE_HEADER {
EFI_GUID CapsuleGuid; EFI_GUID CapsuleGuid;

View file

@ -155,8 +155,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer)
UINT32 capsuleHeaderSize = 0; UINT32 capsuleHeaderSize = 0;
QModelIndex index; QModelIndex index;
if (buffer.startsWith(EFI_CAPSULE_GUID) if (buffer.startsWith(EFI_CAPSULE_GUID)
|| buffer.startsWith(INTEL_CAPSULE_GUID) || buffer.startsWith(INTEL_CAPSULE_GUID)) {
|| buffer.startsWith(LENOVO_CAPSULE_GUID)) {
// Get info // Get info
const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData(); const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData();
capsuleHeaderSize = capsuleHeader->HeaderSize; capsuleHeaderSize = capsuleHeader->HeaderSize;
@ -266,45 +265,36 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor + sizeof(FLASH_DESCRIPTOR_HEADER)); 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_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_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 // Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency
QByteArray gbe; UINT8 descriptorVersion = 0;
UINT32 gbeBegin = 0; if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_20MHZ) // Old descriptor
UINT32 gbeEnd = 0; descriptorVersion = 1;
if (regionSection->GbeLimit) { else if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_17MHZ) // Skylake+ descriptor
gbeBegin = calculateRegionOffset(regionSection->GbeBase); descriptorVersion = 2;
gbeEnd = calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); else {
gbe = intelImage.mid(gbeBegin, gbeEnd); msg(tr("parseIntelImage: unknown descriptor version with ReadClockFreqency %1h").hexarg(componentSection->FlashParameters.ReadClockFreqency));
gbeEnd += gbeBegin; return ERR_INVALID_FLASH_DESCRIPTOR;
} }
// ME region // ME region
QByteArray me; QByteArray me;
UINT32 meBegin = 0; UINT32 meBegin = 0;
UINT32 meEnd = 0; UINT32 meEnd = 0;
if (regionSection->MeLimit) { if (regionSection->Region1Limit) {
meBegin = calculateRegionOffset(regionSection->MeBase); meBegin = calculateRegionOffset(regionSection->Region1Base);
meEnd = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); meEnd = calculateRegionSize(regionSection->Region1Base, regionSection->Region1Limit);
me = intelImage.mid(meBegin, meEnd); me = intelImage.mid(meBegin, meEnd);
meEnd += meBegin; 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 // BIOS region
QByteArray bios; QByteArray bios;
UINT32 biosBegin = 0; UINT32 biosBegin = 0;
UINT32 biosEnd = 0; UINT32 biosEnd = 0;
if (regionSection->BiosLimit) { if (regionSection->Region0Limit) {
biosBegin = calculateRegionOffset(regionSection->BiosBase); biosBegin = calculateRegionOffset(regionSection->Region0Base);
biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); biosEnd = calculateRegionSize(regionSection->Region0Base, regionSection->Region0Limit);
// Check for Gigabyte specific descriptor map // Check for Gigabyte specific descriptor map
if (biosEnd - biosBegin == (UINT32)intelImage.size()) { if (biosEnd - biosBegin == (UINT32)intelImage.size()) {
@ -322,8 +312,41 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor")); msg(tr("parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor"));
return ERR_INVALID_FLASH_DESCRIPTOR; return ERR_INVALID_FLASH_DESCRIPTOR;
} }
// GbE region
QByteArray gbe;
UINT32 gbeBegin = 0;
UINT32 gbeEnd = 0;
if (regionSection->Region2Limit) {
gbeBegin = calculateRegionOffset(regionSection->Region2Base);
gbeEnd = calculateRegionSize(regionSection->Region2Base, regionSection->Region2Limit);
gbe = intelImage.mid(gbeBegin, gbeEnd);
gbeEnd += gbeBegin;
}
// PDR region
QByteArray pdr;
UINT32 pdrBegin = 0;
UINT32 pdrEnd = 0;
if (regionSection->Region3Limit) {
pdrBegin = calculateRegionOffset(regionSection->Region3Base);
pdrEnd = calculateRegionSize(regionSection->Region3Base, regionSection->Region3Limit);
pdr = intelImage.mid(pdrBegin, pdrEnd);
pdrEnd += pdrBegin;
}
// EC region
QByteArray ec;
UINT32 ecBegin = 0;
UINT32 ecEnd = 0;
if (descriptorVersion == 2) {
if (regionSection->Region8Limit) {
pdrBegin = calculateRegionOffset(regionSection->Region8Base);
pdrEnd = calculateRegionSize(regionSection->Region8Base, regionSection->Region8Limit);
pdr = intelImage.mid(ecBegin, ecEnd);
ecEnd += ecBegin;
}
}
// Check for intersections between regions // Check for intersections between regions
// Descriptor
if (hasIntersection(descriptorBegin, descriptorEnd, gbeBegin, gbeEnd)) { if (hasIntersection(descriptorBegin, descriptorEnd, gbeBegin, gbeEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with GbE region")); msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with GbE region"));
return ERR_INVALID_FLASH_DESCRIPTOR; return ERR_INVALID_FLASH_DESCRIPTOR;
@ -340,6 +363,11 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with PDR region")); msg(tr("parseIntelImage: descriptor parsing failed, descriptor region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR; 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)) { if (hasIntersection(gbeBegin, gbeEnd, meBegin, meEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with ME region")); msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with ME region"));
return ERR_INVALID_FLASH_DESCRIPTOR; return ERR_INVALID_FLASH_DESCRIPTOR;
@ -352,6 +380,11 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with PDR region")); msg(tr("parseIntelImage: descriptor parsing failed, GbE region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR; 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)) { if (hasIntersection(meBegin, meEnd, biosBegin, biosEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with BIOS region")); msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with BIOS region"));
return ERR_INVALID_FLASH_DESCRIPTOR; return ERR_INVALID_FLASH_DESCRIPTOR;
@ -360,23 +393,35 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with PDR region")); msg(tr("parseIntelImage: descriptor parsing failed, ME region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR; 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)) { if (hasIntersection(biosBegin, biosEnd, pdrBegin, pdrEnd)) {
msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with PDR region")); msg(tr("parseIntelImage: descriptor parsing failed, BIOS region has intersection with PDR region"));
return ERR_INVALID_FLASH_DESCRIPTOR; 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 // Region map is consistent
// Intel image // Intel image
QString name = tr("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\nMasters: %4\nPCH straps: %5\nCPU straps: %6\n")
.hexarg(intelImage.size()).arg(intelImage.size()) .hexarg(intelImage.size()).arg(intelImage.size())
.arg(descriptorMap->NumberOfFlashChips + 1) // .arg(descriptorMap->NumberOfFlashChips + 1)
.arg(descriptorMap->NumberOfRegions + 1) // Zero-based numbers in storage .arg(descriptorMap->NumberOfMasters + 1)
.arg(descriptorMap->NumberOfMasters + 1) //
.arg(descriptorMap->NumberOfPchStraps) .arg(descriptorMap->NumberOfPchStraps)
.arg(descriptorMap->NumberOfProcStraps) .arg(descriptorMap->NumberOfProcStraps);
.arg(descriptorMap->NumberOfIccTableEntries);
// Add Intel image tree item // Add Intel image tree item
index = model->addItem(Types::Image, Subtypes::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), intelImage, parent); index = model->addItem(Types::Image, Subtypes::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), intelImage, parent);
@ -389,24 +434,30 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
// Check regions presence once again // Check regions presence once again
QVector<UINT32> offsets; QVector<UINT32> offsets;
if (regionSection->GbeLimit) { if (regionSection->Region2Limit) {
offsets.append(gbeBegin); offsets.append(gbeBegin);
info += tr("\nGbE region offset: %1h").hexarg(gbeBegin); info += tr("\nGbE region offset: %1h").hexarg(gbeBegin);
} }
if (regionSection->MeLimit) { if (regionSection->Region1Limit) {
offsets.append(meBegin); offsets.append(meBegin);
info += tr("\nME region offset: %1h").hexarg(meBegin); info += tr("\nME region offset: %1h").hexarg(meBegin);
} }
if (regionSection->BiosLimit) { if (regionSection->Region0Limit) {
offsets.append(biosBegin); offsets.append(biosBegin);
info += tr("\nBIOS region offset: %1h").hexarg(biosBegin); info += tr("\nBIOS region offset: %1h").hexarg(biosBegin);
} }
if (regionSection->PdrLimit) { if (regionSection->Region3Limit) {
offsets.append(pdrBegin); offsets.append(pdrBegin);
info += tr("\nPDR region offset: %1h").hexarg(pdrBegin); info += tr("\nPDR region offset: %1h").hexarg(pdrBegin);
} }
if (descriptorVersion == 2 && regionSection->Region8Limit) {
offsets.append(ecBegin);
info += tr("\nEC region offset: %1h").hexarg(ecBegin);
}
// Region access settings // 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("\nRegion access settings:");
info += tr("\nBIOS:%1%2h ME:%3%4h GbE:%5%6h") info += tr("\nBIOS:%1%2h ME:%3%4h GbE:%5%6h")
.hexarg2(masterSection->BiosRead, 2) .hexarg2(masterSection->BiosRead, 2)
@ -432,6 +483,40 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
info += tr("\nPDR %1 %2") info += tr("\nPDR %1 %2")
.arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ") .arg(masterSection->BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? "Yes " : "No ")
.arg(masterSection->BiosWrite & 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 // VSCC table
const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)(descriptor + ((UINT16)upperMap->VsccTableBase << 4)); const VSCC_TABLE_ENTRY* vsccTableEntry = (const VSCC_TABLE_ENTRY*)(descriptor + ((UINT16)upperMap->VsccTableBase << 4));
@ -474,6 +559,11 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
QModelIndex pdrIndex; QModelIndex pdrIndex;
result = parsePdrRegion(pdr, pdrIndex, index); result = parsePdrRegion(pdr, pdrIndex, index);
} }
// Parse EC region
else if (descriptorVersion == 2 && offsets.at(i) == ecBegin) {
QModelIndex ecIndex;
result = parseEcRegion(ec, ecIndex, index);
}
if (result) if (result)
return result; return result;
} }
@ -489,6 +579,8 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in
IntelDataEnd = biosEnd; IntelDataEnd = biosEnd;
else if (LastRegionOffset == pdrBegin) else if (LastRegionOffset == pdrBegin)
IntelDataEnd = pdrEnd; IntelDataEnd = pdrEnd;
else if (descriptorVersion == 2 && LastRegionOffset == ecBegin)
IntelDataEnd = ecEnd;
if (IntelDataEnd > (UINT32)intelImage.size()) { // Image file is truncated 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") msg(tr("parseIntelImage: image size %1 (%2) is smaller than the end of last region %3 (%4), may be damaged")
@ -615,6 +707,23 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, con
return ERR_SUCCESS; return ERR_SUCCESS;
} }
UINT8 FfsEngine::parseEcRegion(const QByteArray & ec, QModelIndex & index, const QModelIndex & parent, const UINT8 mode)
{
// Check sanity
if (ec.isEmpty())
return ERR_EMPTY_REGION;
// Get info
QString name = tr("EC region");
QString info = tr("Full size: %1h (%2)").
hexarg(ec.size()).arg(ec.size());
// Add tree item
index = model->addItem(Types::Region, Subtypes::EcRegion, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), ec, parent, mode);
return ERR_SUCCESS;
}
UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode) UINT8 FfsEngine::parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode)
{ {
if (bios.isEmpty()) if (bios.isEmpty())
@ -928,10 +1037,10 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// All the rest is either free space or non-UEFI data // All the rest is either free space or non-UEFI data
QByteArray rest = volume.right(volumeSize - fileOffset); QByteArray rest = volume.right(volumeSize - fileOffset);
if (rest.count(empty) == rest.size()) { // It's a free space if (rest.count(empty) == rest.size()) { // It's a free space
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index, mode); model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index);
} }
else { //It's non-UEFI data else { //It's non-UEFI data
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index, mode); QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(rest.size()).arg(rest.size()), QByteArray(), rest, index);
msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex); msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex);
} }
// Exit from loop // Exit from loop
@ -973,16 +1082,16 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co
// Add all bytes before as free space... // Add all bytes before as free space...
if (i > 0) { if (i > 0) {
QByteArray free = freeSpace.left(i); QByteArray free = freeSpace.left(i);
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index, mode); model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(free.size()).arg(free.size()), QByteArray(), free, index);
} }
// ... and all bytes after as a padding // ... and all bytes after as a padding
QByteArray padding = freeSpace.mid(i); QByteArray padding = freeSpace.mid(i);
QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index, mode); QModelIndex dataIndex = model->addItem(Types::Padding, Subtypes::DataPadding, COMPRESSION_ALGORITHM_NONE, tr("Non-UEFI data"), "", tr("Full size: %1h (%2)").hexarg(padding.size()).arg(padding.size()), QByteArray(), padding, index);
msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex); msg(tr("parseVolume: non-UEFI data found in volume's free space"), dataIndex);
} }
else { else {
// Add free space element // Add free space element
model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(freeSpace.size()).arg(freeSpace.size()), QByteArray(), freeSpace, index, mode); model->addItem(Types::FreeSpace, 0, COMPRESSION_ALGORITHM_NONE, tr("Volume free space"), "", tr("Full size: %1h (%2)").hexarg(freeSpace.size()).arg(freeSpace.size()), QByteArray(), freeSpace, index);
} }
break; // Exit from loop break; // Exit from loop
} }
@ -1989,7 +2098,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte
if (header.isEmpty()) // Whole volume if (header.isEmpty()) // Whole volume
volume.append(body); volume.append(body);
else { // Body only else { // Body only
volume.append(model->header(index)).append(body); volume.append(header).append(body);
INT32 sizeDiff = model->body(index).size() - body.size(); INT32 sizeDiff = model->body(index).size() - body.size();
if (sizeDiff > 0) { if (sizeDiff > 0) {
const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)model->header(index).constData(); const EFI_FIRMWARE_VOLUME_HEADER* volumeHeader = (const EFI_FIRMWARE_VOLUME_HEADER*)model->header(index).constData();
@ -2704,17 +2813,37 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec
const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor.constData() + sizeof(FLASH_DESCRIPTOR_HEADER)); const FLASH_DESCRIPTOR_MAP* descriptorMap = (const FLASH_DESCRIPTOR_MAP*)(descriptor.constData() + sizeof(FLASH_DESCRIPTOR_HEADER));
const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->RegionBase); const FLASH_DESCRIPTOR_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->RegionBase);
QByteArray gbe; QByteArray gbe;
UINT32 gbeBegin = calculateRegionOffset(regionSection->GbeBase); UINT32 gbeBegin = calculateRegionOffset(regionSection->Region2Base);
UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->Region2Base, regionSection->Region2Limit);
QByteArray me; QByteArray me;
UINT32 meBegin = calculateRegionOffset(regionSection->MeBase); UINT32 meBegin = calculateRegionOffset(regionSection->Region1Base);
UINT32 meEnd = meBegin + calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); UINT32 meEnd = meBegin + calculateRegionSize(regionSection->Region1Base, regionSection->Region1Limit);
QByteArray bios; QByteArray bios;
UINT32 biosBegin = calculateRegionOffset(regionSection->BiosBase); UINT32 biosBegin = calculateRegionOffset(regionSection->Region0Base);
UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->Region0Base, regionSection->Region0Limit);
QByteArray pdr; QByteArray pdr;
UINT32 pdrBegin = calculateRegionOffset(regionSection->PdrBase); UINT32 pdrBegin = calculateRegionOffset(regionSection->Region3Base);
UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->Region3Base, regionSection->Region3Limit);
QByteArray ec;
UINT32 ecBegin = 0;
UINT32 ecEnd = 0;
const FLASH_DESCRIPTOR_COMPONENT_SECTION* componentSection = (const FLASH_DESCRIPTOR_COMPONENT_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->ComponentBase);
// Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency
UINT8 descriptorVersion = 0;
if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_20MHZ) { // Old descriptor
descriptorVersion = 1;
}
else if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_17MHZ) { // Skylake+ descriptor
descriptorVersion = 2;
ecBegin = calculateRegionOffset(regionSection->Region8Base);
ecEnd = ecBegin + calculateRegionSize(regionSection->Region8Base, regionSection->Region8Limit);
}
else {
msg(tr("reconstructIntelImage: unknown descriptor version with ReadClockFreqency %1h").hexarg(componentSection->FlashParameters.ReadClockFreqency));
return ERR_INVALID_FLASH_DESCRIPTOR;
}
UINT32 offset = descriptor.size(); UINT32 offset = descriptor.size();
// Reconstruct other regions // Reconstruct other regions
@ -2764,6 +2893,17 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec
reconstructed.append(pdr); reconstructed.append(pdr);
offset = pdrEnd; offset = pdrEnd;
break; break;
case Subtypes::EcRegion:
if (descriptorVersion == 1) {
msg(tr("reconstructIntelImage: incompatible region type found"), index);
return ERR_INVALID_REGION;
}
ec = region;
if (ecBegin > offset)
reconstructed.append(QByteArray(ecBegin - offset, empty));
reconstructed.append(ec);
offset = ecEnd;
break;
default: default:
msg(tr("reconstructIntelImage: unknown region type found"), index); msg(tr("reconstructIntelImage: unknown region type found"), index);
return ERR_INVALID_REGION; return ERR_INVALID_REGION;

View file

@ -67,6 +67,7 @@ public:
UINT8 parseMeRegion(const QByteArray & me, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseMeRegion(const QByteArray & me, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseBiosRegion(const QByteArray & bios, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parsePdrRegion(const QByteArray & pdr, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND); UINT8 parsePdrRegion(const QByteArray & pdr, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseEcRegion(const QByteArray & ec, QModelIndex & index, const QModelIndex & parent, const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = QModelIndex()); UINT8 parseBios(const QByteArray & bios, const QModelIndex & parent = QModelIndex());
UINT8 parseVolume(const QByteArray & volume, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseVolume(const QByteArray & volume, QModelIndex & index, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);
UINT8 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND); UINT8 parseFile(const QByteArray & file, QModelIndex & index, const UINT8 erasePolarity = ERASE_POLARITY_UNKNOWN, const QModelIndex & parent = QModelIndex(), const UINT8 mode = CREATE_MODE_APPEND);

View file

@ -29,6 +29,8 @@ QString regionTypeToQString(const UINT8 type)
return QObject::tr("BIOS"); return QObject::tr("BIOS");
case Subtypes::PdrRegion: case Subtypes::PdrRegion:
return QObject::tr("PDR"); return QObject::tr("PDR");
case Subtypes::EcRegion:
return QObject::tr("EC");
default: default:
return QObject::tr("Unknown"); return QObject::tr("Unknown");
}; };

View file

@ -69,7 +69,8 @@ namespace Subtypes {
GbeRegion, GbeRegion,
MeRegion, MeRegion,
BiosRegion, BiosRegion,
PdrRegion PdrRegion,
EcRegion
}; };
enum PaddingSubtypes { enum PaddingSubtypes {

View file

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