mirror of
https://github.com/LongSoft/UEFITool.git
synced 2024-11-29 19:38:22 +08:00
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:
parent
9c4ddbec62
commit
aa80837bf5
131
descriptor.h
131
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
|
||||
|
4
ffs.h
4
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;
|
||||
|
292
ffsengine.cpp
292
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<UINT32> 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;
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
};
|
||||
|
3
types.h
3
types.h
@ -69,7 +69,8 @@ namespace Subtypes {
|
||||
GbeRegion,
|
||||
MeRegion,
|
||||
BiosRegion,
|
||||
PdrRegion
|
||||
PdrRegion,
|
||||
EcRegion
|
||||
};
|
||||
|
||||
enum PaddingSubtypes {
|
||||
|
@ -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();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user