From aa80837bf5ce68af01f1f432011b546cd8762bef Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sun, 6 Sep 2015 23:46:26 +0200 Subject: [PATCH] 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 --- descriptor.h | 131 ++++++++++++++-------- ffs.h | 4 - ffsengine.cpp | 292 +++++++++++++++++++++++++++++++++++++------------- ffsengine.h | 1 + types.cpp | 2 + types.h | 3 +- uefitool.cpp | 2 +- 7 files changed, 309 insertions(+), 126 deletions(-) diff --git a/descriptor.h b/descriptor.h index 82ff6da..989761b 100644 --- a/descriptor.h +++ b/descriptor.h @@ -17,7 +17,7 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "basetypes.h" // Make sure we use right packing rules -#pragma pack(push,1) +#pragma pack(push, 1) // Flash descriptor header typedef struct _FLASH_DESCRIPTOR_HEADER { @@ -34,37 +34,38 @@ 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 : 8; + // FLMAP 1 + UINT32 MasterBase : 8; + UINT32 NumberOfMasters : 2; + 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 ReadClockFreqency : 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 FlashWriteFrequency : 3; UINT8 DualOutputFastReadSupported : 1; - UINT8 ReservedZero3 : 1; // Still unknown, zero in all descriptors I have seen + UINT8 : 1; } FLASH_PARAMETERS; // Flash densities @@ -74,11 +75,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_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 { @@ -87,24 +93,45 @@ typedef struct _FLASH_DESCRIPTOR_COMPONENT_SECTION { 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 ReservedZero; // Still unknown, zero in all descriptors I have seen } 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 // 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 :16; 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 Region0Base; // BIOS + UINT16 Region0Limit; // + UINT16 Region1Base; // ME + UINT16 Region1Limit; // + UINT16 Region2Base; // GbE + UINT16 Region2Limit; // + UINT16 Region3Base; // PDR + 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 block erase sizes @@ -115,24 +142,40 @@ typedef struct _FLASH_DESCRIPTOR_REGION_SECTION { // Master section typedef struct _FLASH_DESCRIPTOR_MASTER_SECTION { UINT16 BiosId; - UINT8 BiosRead; - UINT8 BiosWrite; + UINT8 BiosRead; + UINT8 BiosWrite; UINT16 MeId; - UINT8 MeRead; - UINT8 MeWrite; + UINT8 MeRead; + UINT8 MeWrite; UINT16 GbeId; - UINT8 GbeRead; - UINT8 GbeWrite; + 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 - -//!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 diff --git a/ffs.h b/ffs.h index 0bb8221..0adc031 100644 --- a/ffs.h +++ b/ffs.h @@ -53,10 +53,6 @@ const QByteArray EFI_CAPSULE_GUID const QByteArray INTEL_CAPSULE_GUID ("\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 typedef struct _TOSHIBA_CAPSULE_HEADER { EFI_GUID CapsuleGuid; diff --git a/ffsengine.cpp b/ffsengine.cpp index d516019..985ea38 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -155,8 +155,7 @@ UINT8 FfsEngine::parseImageFile(const QByteArray & buffer) UINT32 capsuleHeaderSize = 0; QModelIndex index; if (buffer.startsWith(EFI_CAPSULE_GUID) - || buffer.startsWith(INTEL_CAPSULE_GUID) - || buffer.startsWith(LENOVO_CAPSULE_GUID)) { + || buffer.startsWith(INTEL_CAPSULE_GUID)) { // Get info const EFI_CAPSULE_HEADER* capsuleHeader = (const EFI_CAPSULE_HEADER*)buffer.constData(); 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_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.ReadClockFreqency == FLASH_FREQUENCY_20MHZ) // Old descriptor + descriptorVersion = 1; + else if (componentSection->FlashParameters.ReadClockFreqency == FLASH_FREQUENCY_17MHZ) // Skylake+ descriptor + descriptorVersion = 2; + else { + msg(tr("parseIntelImage: unknown descriptor version with ReadClockFreqency %1h").hexarg(componentSection->FlashParameters.ReadClockFreqency)); + return ERR_INVALID_FLASH_DESCRIPTOR; } + // ME region QByteArray me; UINT32 meBegin = 0; UINT32 meEnd = 0; - if (regionSection->MeLimit) { - meBegin = calculateRegionOffset(regionSection->MeBase); - meEnd = calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); + if (regionSection->Region1Limit) { + meBegin = calculateRegionOffset(regionSection->Region1Base); + meEnd = calculateRegionSize(regionSection->Region1Base, regionSection->Region1Limit); 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; UINT32 biosEnd = 0; - if (regionSection->BiosLimit) { - biosBegin = calculateRegionOffset(regionSection->BiosBase); - biosEnd = calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); + if (regionSection->Region0Limit) { + biosBegin = calculateRegionOffset(regionSection->Region0Base); + biosEnd = calculateRegionSize(regionSection->Region0Base, regionSection->Region0Limit); // Check for Gigabyte specific descriptor map 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")); 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 + // 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; @@ -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")); 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; @@ -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")); 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; @@ -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")); 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\nMasters: %4\nPCH straps: %5\nCPU straps: %6\n") .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->NumberOfFlashChips + 1) + .arg(descriptorMap->NumberOfMasters + 1) .arg(descriptorMap->NumberOfPchStraps) - .arg(descriptorMap->NumberOfProcStraps) - .arg(descriptorMap->NumberOfIccTableEntries); + .arg(descriptorMap->NumberOfProcStraps); // Add Intel image tree item index = model->addItem(Types::Image, Subtypes::IntelImage, COMPRESSION_ALGORITHM_NONE, name, "", info, QByteArray(), intelImage, parent); @@ -389,49 +434,89 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in // Check regions presence once again QVector offsets; - if (regionSection->GbeLimit) { + if (regionSection->Region2Limit) { offsets.append(gbeBegin); info += tr("\nGbE region offset: %1h").hexarg(gbeBegin); } - if (regionSection->MeLimit) { + if (regionSection->Region1Limit) { offsets.append(meBegin); info += tr("\nME region offset: %1h").hexarg(meBegin); } - if (regionSection->BiosLimit) { + if (regionSection->Region0Limit) { offsets.append(biosBegin); info += tr("\nBIOS region offset: %1h").hexarg(biosBegin); } - if (regionSection->PdrLimit) { + if (regionSection->Region3Limit) { offsets.append(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 - info += tr("\nRegion access settings:"); - info += tr("\nBIOS:%1%2h ME:%3%4h GbE:%5%6h") - .hexarg2(masterSection->BiosRead, 2) - .hexarg2(masterSection->BiosWrite, 2) - .hexarg2(masterSection->MeRead, 2) - .hexarg2(masterSection->MeWrite, 2) - .hexarg2(masterSection->GbeRead, 2) - .hexarg2(masterSection->GbeWrite, 2); + 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") + .hexarg2(masterSection->BiosRead, 2) + .hexarg2(masterSection->BiosWrite, 2) + .hexarg2(masterSection->MeRead, 2) + .hexarg2(masterSection->MeWrite, 2) + .hexarg2(masterSection->GbeRead, 2) + .hexarg2(masterSection->GbeWrite, 2); - // 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 "); + // 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 "); + } + 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)); @@ -474,6 +559,11 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in QModelIndex pdrIndex; 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) return result; } @@ -489,6 +579,8 @@ UINT8 FfsEngine::parseIntelImage(const QByteArray & intelImage, QModelIndex & in 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") @@ -615,6 +707,23 @@ UINT8 FfsEngine::parsePdrRegion(const QByteArray & pdr, QModelIndex & index, con 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) { 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 QByteArray rest = volume.right(volumeSize - fileOffset); 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 - 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); } // Exit from loop @@ -973,16 +1082,16 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co // Add all bytes before as free space... if (i > 0) { 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 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); } else { // 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 } @@ -1989,7 +2098,7 @@ UINT8 FfsEngine::create(const QModelIndex & index, const UINT8 type, const QByte if (header.isEmpty()) // Whole volume volume.append(body); else { // Body only - volume.append(model->header(index)).append(body); + volume.append(header).append(body); INT32 sizeDiff = model->body(index).size() - body.size(); if (sizeDiff > 0) { 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_REGION_SECTION* regionSection = (const FLASH_DESCRIPTOR_REGION_SECTION*)calculateAddress8((const UINT8*)descriptor.constData(), descriptorMap->RegionBase); QByteArray gbe; - UINT32 gbeBegin = calculateRegionOffset(regionSection->GbeBase); - UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->GbeBase, regionSection->GbeLimit); + UINT32 gbeBegin = calculateRegionOffset(regionSection->Region2Base); + UINT32 gbeEnd = gbeBegin + calculateRegionSize(regionSection->Region2Base, regionSection->Region2Limit); QByteArray me; - UINT32 meBegin = calculateRegionOffset(regionSection->MeBase); - UINT32 meEnd = meBegin + calculateRegionSize(regionSection->MeBase, regionSection->MeLimit); + UINT32 meBegin = calculateRegionOffset(regionSection->Region1Base); + UINT32 meEnd = meBegin + calculateRegionSize(regionSection->Region1Base, regionSection->Region1Limit); QByteArray bios; - UINT32 biosBegin = calculateRegionOffset(regionSection->BiosBase); - UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->BiosBase, regionSection->BiosLimit); + UINT32 biosBegin = calculateRegionOffset(regionSection->Region0Base); + UINT32 biosEnd = biosBegin + calculateRegionSize(regionSection->Region0Base, regionSection->Region0Limit); QByteArray pdr; - UINT32 pdrBegin = calculateRegionOffset(regionSection->PdrBase); - UINT32 pdrEnd = pdrBegin + calculateRegionSize(regionSection->PdrBase, regionSection->PdrLimit); + UINT32 pdrBegin = calculateRegionOffset(regionSection->Region3Base); + 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(); // Reconstruct other regions @@ -2764,6 +2893,17 @@ UINT8 FfsEngine::reconstructIntelImage(const QModelIndex& index, QByteArray& rec reconstructed.append(pdr); offset = pdrEnd; 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: msg(tr("reconstructIntelImage: unknown region type found"), index); return ERR_INVALID_REGION; diff --git a/ffsengine.h b/ffsengine.h index 281aa6e..c565921 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -67,6 +67,7 @@ public: 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 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 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); diff --git a/types.cpp b/types.cpp index 17ca51f..a9a9300 100644 --- a/types.cpp +++ b/types.cpp @@ -29,6 +29,8 @@ QString regionTypeToQString(const UINT8 type) return QObject::tr("BIOS"); case Subtypes::PdrRegion: return QObject::tr("PDR"); + case Subtypes::EcRegion: + return QObject::tr("EC"); default: return QObject::tr("Unknown"); }; diff --git a/types.h b/types.h index 64df300..7d71953 100644 --- a/types.h +++ b/types.h @@ -69,7 +69,8 @@ namespace Subtypes { GbeRegion, MeRegion, BiosRegion, - PdrRegion + PdrRegion, + EcRegion }; enum PaddingSubtypes { diff --git a/uefitool.cpp b/uefitool.cpp index 5a4ef55..39d77ce 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.20.8")) +version(tr("0.21.0")) { clipboard = QApplication::clipboard();