2014-05-03 19:21:03 +08:00
/* ffsengine.cpp
2015-01-31 22:00:00 +08:00
Copyright ( c ) 2015 , Nikolaj Schlej . All rights reserved .
2014-05-03 19:21:03 +08:00
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution . The full text of the license may be found at
http : //opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN " AS IS " BASIS ,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND , EITHER EXPRESS OR IMPLIED .
*/
# include <math.h>
# include "ffsengine.h"
# include "types.h"
# include "treemodel.h"
# include "descriptor.h"
# include "ffs.h"
# include "gbe.h"
# include "me.h"
# include "Tiano/EfiTianoCompress.h"
# include "Tiano/EfiTianoDecompress.h"
# include "LZMA/LzmaCompress.h"
# include "LZMA/LzmaDecompress.h"
# ifdef _CONSOLE
# include <iostream>
# endif
2014-07-12 18:27:42 +08:00
QString errorMessage ( UINT8 errorCode )
{
2015-01-31 22:00:00 +08:00
switch ( errorCode ) {
case ERR_SUCCESS : return QObject : : tr ( " Success " ) ;
case ERR_NOT_IMPLEMENTED : return QObject : : tr ( " Not implemented " ) ;
case ERR_INVALID_PARAMETER : return QObject : : tr ( " Function called with invalid parameter " ) ;
case ERR_BUFFER_TOO_SMALL : return QObject : : tr ( " Buffer too small " ) ;
case ERR_OUT_OF_RESOURCES : return QObject : : tr ( " Out of resources " ) ;
case ERR_OUT_OF_MEMORY : return QObject : : tr ( " Out of memory " ) ;
case ERR_FILE_OPEN : return QObject : : tr ( " File can't be opened " ) ;
case ERR_FILE_READ : return QObject : : tr ( " File can't be read " ) ;
case ERR_FILE_WRITE : return QObject : : tr ( " File can't be written " ) ;
case ERR_ITEM_NOT_FOUND : return QObject : : tr ( " Item not found " ) ;
case ERR_UNKNOWN_ITEM_TYPE : return QObject : : tr ( " Unknown item type " ) ;
case ERR_INVALID_FLASH_DESCRIPTOR : return QObject : : tr ( " Invalid flash descriptor " ) ;
case ERR_INVALID_REGION : return QObject : : tr ( " Invalid region " ) ;
case ERR_EMPTY_REGION : return QObject : : tr ( " Empty region " ) ;
case ERR_BIOS_REGION_NOT_FOUND : return QObject : : tr ( " BIOS region not found " ) ;
case ERR_VOLUMES_NOT_FOUND : return QObject : : tr ( " UEFI volumes not found " ) ;
case ERR_INVALID_VOLUME : return QObject : : tr ( " Invalid UEFI volume " ) ;
case ERR_VOLUME_REVISION_NOT_SUPPORTED : return QObject : : tr ( " Volume revision not supported " ) ;
case ERR_VOLUME_GROW_FAILED : return QObject : : tr ( " Volume grow failed " ) ;
case ERR_UNKNOWN_FFS : return QObject : : tr ( " Unknown file system " ) ;
case ERR_INVALID_FILE : return QObject : : tr ( " Invalid file " ) ;
case ERR_INVALID_SECTION : return QObject : : tr ( " Invalid section " ) ;
case ERR_UNKNOWN_SECTION : return QObject : : tr ( " Unknown section " ) ;
case ERR_STANDARD_COMPRESSION_FAILED : return QObject : : tr ( " Standard compression failed " ) ;
case ERR_CUSTOMIZED_COMPRESSION_FAILED : return QObject : : tr ( " Customized compression failed " ) ;
case ERR_STANDARD_DECOMPRESSION_FAILED : return QObject : : tr ( " Standard decompression failed " ) ;
case ERR_CUSTOMIZED_DECOMPRESSION_FAILED : return QObject : : tr ( " Customized compression failed " ) ;
case ERR_UNKNOWN_COMPRESSION_ALGORITHM : return QObject : : tr ( " Unknown compression method " ) ;
case ERR_UNKNOWN_EXTRACT_MODE : return QObject : : tr ( " Unknown extract mode " ) ;
case ERR_UNKNOWN_INSERT_MODE : return QObject : : tr ( " Unknown insert mode " ) ;
case ERR_UNKNOWN_IMAGE_TYPE : return QObject : : tr ( " Unknown executable image type " ) ;
case ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE : return QObject : : tr ( " Unknown PE optional header type " ) ;
case ERR_UNKNOWN_RELOCATION_TYPE : return QObject : : tr ( " Unknown relocation type " ) ;
case ERR_GENERIC_CALL_NOT_SUPPORTED : return QObject : : tr ( " Generic call not supported " ) ;
case ERR_VOLUME_BASE_NOT_FOUND : return QObject : : tr ( " Volume base address not found " ) ;
case ERR_PEI_CORE_ENTRY_POINT_NOT_FOUND : return QObject : : tr ( " PEI core entry point not found " ) ;
case ERR_COMPLEX_BLOCK_MAP : return QObject : : tr ( " Block map structure too complex for correct analysis " ) ;
case ERR_DIR_ALREADY_EXIST : return QObject : : tr ( " Directory already exists " ) ;
case ERR_DIR_CREATE : return QObject : : tr ( " Directory can't be created " ) ;
case ERR_UNKNOWN_PATCH_TYPE : return QObject : : tr ( " Unknown patch type " ) ;
case ERR_PATCH_OFFSET_OUT_OF_BOUNDS : return QObject : : tr ( " Patch offset out of bounds " ) ;
case ERR_INVALID_SYMBOL : return QObject : : tr ( " Invalid symbol " ) ;
case ERR_NOTHING_TO_PATCH : return QObject : : tr ( " Nothing to patch " ) ;
case ERR_DEPEX_PARSE_FAILED : return QObject : : tr ( " Dependency expression parsing failed " ) ;
default : return QObject : : tr ( " Unknown error %1 " ) . arg ( errorCode ) ;
2014-07-12 18:27:42 +08:00
}
}
2014-05-03 19:21:03 +08:00
FfsEngine : : FfsEngine ( QObject * parent )
2014-07-25 07:59:51 +08:00
: QObject ( parent )
2014-05-03 19:21:03 +08:00
{
model = new TreeModel ( ) ;
oldPeiCoreEntryPoint = 0 ;
newPeiCoreEntryPoint = 0 ;
2014-10-30 12:34:19 +08:00
dumped = false ;
2014-05-03 19:21:03 +08:00
}
FfsEngine : : ~ FfsEngine ( void )
{
delete model ;
}
TreeModel * FfsEngine : : treeModel ( ) const
{
return model ;
}
void FfsEngine : : msg ( const QString & message , const QModelIndex & index )
{
2014-12-19 16:20:36 +08:00
# ifndef _DISABLE_ENGINE_MESSAGES
2014-07-25 07:59:51 +08:00
# ifndef _CONSOLE
2014-05-03 19:21:03 +08:00
messageItems . enqueue ( MessageListItem ( message , NULL , 0 , index ) ) ;
# else
2014-11-09 06:30:32 +08:00
( void ) index ;
2014-11-18 23:01:20 +08:00
std : : cout < < message . toLatin1 ( ) . constData ( ) < < std : : endl ;
2014-05-03 19:21:03 +08:00
# endif
2014-12-19 16:20:36 +08:00
# else
( void ) message ;
( void ) index ;
# endif
2014-05-03 19:21:03 +08:00
}
# ifndef _CONSOLE
QQueue < MessageListItem > FfsEngine : : messages ( ) const
{
return messageItems ;
}
void FfsEngine : : clearMessages ( )
{
messageItems . clear ( ) ;
}
# endif
bool FfsEngine : : hasIntersection ( const UINT32 begin1 , const UINT32 end1 , const UINT32 begin2 , const UINT32 end2 )
{
if ( begin1 < begin2 & & begin2 < end1 )
return true ;
if ( begin1 < end2 & & end2 < end1 )
return true ;
if ( begin2 < begin1 & & begin1 < end2 )
return true ;
if ( begin2 < end1 & & end1 < end2 )
return true ;
return false ;
}
// Firmware image parsing
UINT8 FfsEngine : : parseImageFile ( const QByteArray & buffer )
{
oldPeiCoreEntryPoint = 0 ;
newPeiCoreEntryPoint = 0 ;
// Check buffer size to be more then or equal to size of EFI_CAPSULE_HEADER
2015-01-31 22:00:00 +08:00
if ( ( UINT32 ) buffer . size ( ) < = sizeof ( EFI_CAPSULE_HEADER ) ) {
2015-02-18 22:35:44 +08:00
msg ( tr ( " parseImageFile: image file is smaller then minimum size of %1h (%2) bytes " ) . hexarg ( sizeof ( EFI_CAPSULE_HEADER ) ) . arg ( sizeof ( EFI_CAPSULE_HEADER ) ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_PARAMETER ;
}
// Check buffer for being normal EFI capsule header
2015-01-31 22:00:00 +08:00
UINT32 capsuleHeaderSize = 0 ;
QModelIndex index ;
2014-05-03 19:21:03 +08:00
if ( buffer . startsWith ( EFI_CAPSULE_GUID ) ) {
// Get info
2015-01-31 22:00:00 +08:00
const EFI_CAPSULE_HEADER * capsuleHeader = ( const EFI_CAPSULE_HEADER * ) buffer . constData ( ) ;
2014-05-03 19:21:03 +08:00
capsuleHeaderSize = capsuleHeader - > HeaderSize ;
QByteArray header = buffer . left ( capsuleHeaderSize ) ;
QByteArray body = buffer . right ( buffer . size ( ) - capsuleHeaderSize ) ;
QString name = tr ( " UEFI capsule " ) ;
2015-01-31 22:00:00 +08:00
QString info = tr ( " Capsule GUID: %1 \n Full size: %2h (%3) \n Header size: %4h (%5) \n Image size: %6h (%7) \n Flags: %8h " )
. arg ( guidToQString ( capsuleHeader - > CapsuleGuid ) )
. hexarg ( buffer . size ( ) ) . arg ( buffer . size ( ) )
. hexarg ( capsuleHeader - > HeaderSize ) . arg ( capsuleHeader - > HeaderSize )
. hexarg ( capsuleHeader - > CapsuleImageSize ) . arg ( capsuleHeader - > CapsuleImageSize )
. hexarg2 ( capsuleHeader - > Flags , 8 ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Capsule , Subtypes : : UefiCapsule , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body ) ;
2014-05-03 19:21:03 +08:00
}
2015-01-31 22:00:00 +08:00
// Check buffer for being extended Aptio signed capsule header
else if ( buffer . startsWith ( APTIO_SIGNED_CAPSULE_GUID ) | | buffer . startsWith ( APTIO_UNSIGNED_CAPSULE_GUID ) ) {
2014-05-03 19:21:03 +08:00
// Get info
2015-01-31 22:00:00 +08:00
bool signedCapsule = buffer . startsWith ( APTIO_SIGNED_CAPSULE_GUID ) ;
const APTIO_CAPSULE_HEADER * capsuleHeader = ( const APTIO_CAPSULE_HEADER * ) buffer . constData ( ) ;
capsuleHeaderSize = capsuleHeader - > RomImageOffset ;
2014-05-03 19:21:03 +08:00
QByteArray header = buffer . left ( capsuleHeaderSize ) ;
QByteArray body = buffer . right ( buffer . size ( ) - capsuleHeaderSize ) ;
QString name = tr ( " AMI Aptio capsule " ) ;
2015-01-31 22:00:00 +08:00
QString info = tr ( " Capsule GUID: %1 \n Full size: %2h (%3) \n Header size: %4h (%5) \n Image size: %6h (%7) \n Flags: %8h " )
. arg ( guidToQString ( capsuleHeader - > CapsuleHeader . CapsuleGuid ) )
. hexarg ( buffer . size ( ) ) . arg ( buffer . size ( ) )
. hexarg ( capsuleHeaderSize ) . arg ( capsuleHeaderSize )
. hexarg ( capsuleHeader - > CapsuleHeader . CapsuleImageSize - capsuleHeaderSize ) . arg ( capsuleHeader - > CapsuleHeader . CapsuleImageSize - capsuleHeaderSize )
. hexarg2 ( capsuleHeader - > CapsuleHeader . Flags , 8 ) ;
2014-05-03 19:21:03 +08:00
//!TODO: more info about Aptio capsule
2015-01-31 22:00:00 +08:00
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Capsule , signedCapsule ? Subtypes : : AptioSignedCapsule : Subtypes : : AptioUnsignedCapsule , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body ) ;
2015-01-31 22:00:00 +08:00
// Show message about possible Aptio signature break
if ( signedCapsule ) {
msg ( tr ( " parseImageFile: Aptio capsule signature may become invalid after image modifications " ) , index ) ;
}
2014-05-03 19:21:03 +08:00
}
// Skip capsule header to have flash chip image
2015-01-31 22:00:00 +08:00
QByteArray flashImage = buffer . right ( buffer . size ( ) - capsuleHeaderSize ) ;
2014-05-03 19:21:03 +08:00
// Check for Intel flash descriptor presence
2015-01-31 22:00:00 +08:00
const FLASH_DESCRIPTOR_HEADER * descriptorHeader = ( const FLASH_DESCRIPTOR_HEADER * ) flashImage . constData ( ) ;
2014-05-03 19:21:03 +08:00
// Check descriptor signature
UINT8 result ;
if ( descriptorHeader - > Signature = = FLASH_DESCRIPTOR_SIGNATURE ) {
// Parse as Intel image
QModelIndex imageIndex ;
result = parseIntelImage ( flashImage , imageIndex , index ) ;
if ( result ! = ERR_INVALID_FLASH_DESCRIPTOR )
return result ;
}
// Get info
2015-01-31 22:00:00 +08:00
QString name = tr ( " UEFI image " ) ;
QString info = tr ( " Full size: %1h (%2) " )
. hexarg ( flashImage . size ( ) ) . arg ( flashImage . size ( ) ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Image , Subtypes : : UefiImage , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , flashImage , QByteArray ( ) , index ) ;
2014-05-03 19:21:03 +08:00
return parseBios ( flashImage , index ) ;
}
UINT8 FfsEngine : : parseIntelImage ( const QByteArray & intelImage , QModelIndex & index , const QModelIndex & parent )
{
2015-01-31 22:00:00 +08:00
// Sanity check
if ( intelImage . isEmpty ( ) )
return EFI_INVALID_PARAMETER ;
2014-05-03 19:21:03 +08:00
// Store the beginning of descriptor as descriptor base address
2015-01-31 22:00:00 +08:00
const UINT8 * descriptor = ( const UINT8 * ) intelImage . constData ( ) ;
2014-05-03 19:21:03 +08:00
UINT32 descriptorBegin = 0 ;
UINT32 descriptorEnd = FLASH_DESCRIPTOR_SIZE ;
// Check for buffer size to be greater or equal to descriptor region size
if ( intelImage . size ( ) < FLASH_DESCRIPTOR_SIZE ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseIntelImage: input file is smaller then minimum descriptor size of %1h (%2) bytes " ) . hexarg ( FLASH_DESCRIPTOR_SIZE ) . arg ( FLASH_DESCRIPTOR_SIZE ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
// Parse descriptor map
2015-01-31 22:00:00 +08:00
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 ) ;
2014-05-03 19:21:03 +08:00
// 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 ;
}
// ME region
QByteArray me ;
UINT32 meBegin = 0 ;
UINT32 meEnd = 0 ;
if ( regionSection - > MeLimit ) {
meBegin = calculateRegionOffset ( regionSection - > MeBase ) ;
meEnd = calculateRegionSize ( regionSection - > MeBase , regionSection - > MeLimit ) ;
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 ) ;
2014-07-25 07:59:51 +08:00
2014-07-09 15:20:13 +08:00
// Check for Gigabyte specific descriptor map
2014-11-08 01:16:33 +08:00
if ( biosEnd - biosBegin = = ( UINT32 ) intelImage . size ( ) ) {
2014-07-09 15:20:13 +08:00
if ( ! meEnd ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseIntelImage: can't determine BIOS region start from Gigabyte-specific descriptor " ) ) ;
2014-07-09 15:20:13 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
biosBegin = meEnd ;
}
2014-07-25 07:59:51 +08:00
2014-05-03 19:21:03 +08:00
bios = intelImage . mid ( biosBegin , biosEnd ) ;
biosEnd + = biosBegin ;
}
else {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, BIOS region not found in descriptor " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
// Check for intersections between regions
if ( hasIntersection ( descriptorBegin , descriptorEnd , gbeBegin , gbeEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, descriptor region has intersection with GbE region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( descriptorBegin , descriptorEnd , meBegin , meEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, descriptor region has intersection with ME region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( descriptorBegin , descriptorEnd , biosBegin , biosEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, descriptor region has intersection with BIOS region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( descriptorBegin , descriptorEnd , pdrBegin , pdrEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, descriptor region has intersection with PDR region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( gbeBegin , gbeEnd , meBegin , meEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, GbE region has intersection with ME region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( gbeBegin , gbeEnd , biosBegin , biosEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, GbE region has intersection with BIOS region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( gbeBegin , gbeEnd , pdrBegin , pdrEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, GbE region has intersection with PDR region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( meBegin , meEnd , biosBegin , biosEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, ME region has intersection with BIOS region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( meBegin , meEnd , pdrBegin , pdrEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, ME region has intersection with PDR region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
if ( hasIntersection ( biosBegin , biosEnd , pdrBegin , pdrEnd ) ) {
2014-07-09 15:20:13 +08:00
msg ( tr ( " parseIntelImage: descriptor parsing failed, BIOS region has intersection with PDR region " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FLASH_DESCRIPTOR ;
}
2014-07-25 07:59:51 +08:00
2014-05-03 19:21:03 +08:00
// Region map is consistent
// Intel image
2015-01-31 22:00:00 +08:00
QString name = tr ( " Intel image " ) ;
QString info = tr ( " Full size: %1h (%2) \n Flash chips: %3 \n Regions: %4 \n Masters: %5 \n PCH straps: %6 \n PROC straps: %7 \n ICC table entries: %8 " )
. hexarg ( intelImage . size ( ) ) . arg ( intelImage . size ( ) )
2014-05-03 19:21:03 +08:00
. arg ( descriptorMap - > NumberOfFlashChips + 1 ) //
. arg ( descriptorMap - > NumberOfRegions + 1 ) // Zero-based numbers in storage
. arg ( descriptorMap - > NumberOfMasters + 1 ) //
. arg ( descriptorMap - > NumberOfPchStraps )
. arg ( descriptorMap - > NumberOfProcStraps )
. arg ( descriptorMap - > NumberOfIccTableEntries ) ;
// Add Intel image tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Image , Subtypes : : IntelImage , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , intelImage , QByteArray ( ) , parent ) ;
2014-05-03 19:21:03 +08:00
// Descriptor
// Get descriptor info
2015-01-31 22:00:00 +08:00
QByteArray body = intelImage . left ( FLASH_DESCRIPTOR_SIZE ) ;
2014-05-03 19:21:03 +08:00
name = tr ( " Descriptor region " ) ;
2015-01-31 22:00:00 +08:00
info = tr ( " Full size: %1h (%2) " ) . hexarg ( FLASH_DESCRIPTOR_SIZE ) . arg ( FLASH_DESCRIPTOR_SIZE ) ;
2014-05-03 19:21:03 +08:00
// Check regions presence once again
QVector < UINT32 > offsets ;
if ( regionSection - > GbeLimit ) {
offsets . append ( gbeBegin ) ;
2015-01-31 22:00:00 +08:00
info + = tr ( " \n GbE region offset: %1h " ) . hexarg ( gbeBegin ) ;
2014-05-03 19:21:03 +08:00
}
if ( regionSection - > MeLimit ) {
offsets . append ( meBegin ) ;
2015-01-31 22:00:00 +08:00
info + = tr ( " \n ME region offset: %1h " ) . hexarg ( meBegin ) ;
2014-05-03 19:21:03 +08:00
}
if ( regionSection - > BiosLimit ) {
offsets . append ( biosBegin ) ;
2015-01-31 22:00:00 +08:00
info + = tr ( " \n BIOS region offset: %1h " ) . hexarg ( biosBegin ) ;
2014-05-03 19:21:03 +08:00
}
if ( regionSection - > PdrLimit ) {
offsets . append ( pdrBegin ) ;
2015-01-31 22:00:00 +08:00
info + = tr ( " \n PDR region offset: %1h " ) . hexarg ( pdrBegin ) ;
2014-05-03 19:21:03 +08:00
}
// Region access settings
info + = tr ( " \n Region access settings: " ) ;
2015-01-31 22:00:00 +08:00
info + = tr ( " \n BIOS:%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 ) ;
2014-05-03 19:21:03 +08:00
// BIOS access table
info + = tr ( " \n BIOS access table: " ) ;
info + = tr ( " \n Read Write " ) ;
info + = tr ( " \n Desc %1 %2 " )
. arg ( masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? " Yes " : " No " )
. arg ( masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? " Yes " : " No " ) ;
info + = tr ( " \n BIOS Yes Yes " ) ;
info + = tr ( " \n ME %1 %2 " )
. arg ( masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " )
. arg ( masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ) ;
info + = tr ( " \n GbE %1 %2 " )
. arg ( masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " )
. arg ( masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ) ;
info + = tr ( " \n PDR %1 %2 " )
. arg ( masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " )
. arg ( masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " ) ;
// VSCC table
2015-01-31 22:00:00 +08:00
const VSCC_TABLE_ENTRY * vsccTableEntry = ( const VSCC_TABLE_ENTRY * ) ( descriptor + ( ( UINT16 ) upperMap - > VsccTableBase < < 4 ) ) ;
2014-11-18 23:01:20 +08:00
info + = tr ( " \n Flash chips in VSCC table: " ) ;
UINT8 vsscTableSize = upperMap - > VsccTableSize * sizeof ( UINT32 ) / sizeof ( VSCC_TABLE_ENTRY ) ;
for ( int i = 0 ; i < vsscTableSize ; i + + ) {
2015-01-31 22:00:00 +08:00
info + = tr ( " \n %1%2%3h " )
. hexarg2 ( vsccTableEntry - > VendorId , 2 )
. hexarg2 ( vsccTableEntry - > DeviceId0 , 2 )
. hexarg2 ( vsccTableEntry - > DeviceId1 , 2 ) ;
2014-11-18 23:01:20 +08:00
vsccTableEntry + + ;
}
2014-05-03 19:21:03 +08:00
// Add descriptor tree item
2015-02-06 16:47:19 +08:00
model - > addItem ( Types : : Region , Subtypes : : DescriptorRegion , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , body , QByteArray ( ) , index ) ;
2014-07-25 07:59:51 +08:00
2014-05-03 19:21:03 +08:00
// Sort regions in ascending order
qSort ( offsets ) ;
// Parse regions
UINT8 result = 0 ;
for ( int i = 0 ; i < offsets . count ( ) ; i + + ) {
// Parse GbE region
if ( offsets . at ( i ) = = gbeBegin ) {
QModelIndex gbeIndex ;
result = parseGbeRegion ( gbe , gbeIndex , index ) ;
}
// Parse ME region
else if ( offsets . at ( i ) = = meBegin ) {
QModelIndex meIndex ;
result = parseMeRegion ( me , meIndex , index ) ;
}
// Parse BIOS region
else if ( offsets . at ( i ) = = biosBegin ) {
QModelIndex biosIndex ;
result = parseBiosRegion ( bios , biosIndex , index ) ;
}
// Parse PDR region
else if ( offsets . at ( i ) = = pdrBegin ) {
QModelIndex pdrIndex ;
result = parsePdrRegion ( pdr , pdrIndex , index ) ;
}
if ( result )
return result ;
}
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : parseGbeRegion ( const QByteArray & gbe , QModelIndex & index , const QModelIndex & parent , const UINT8 mode )
{
2015-01-31 22:00:00 +08:00
// Check sanity
2014-05-03 19:21:03 +08:00
if ( gbe . isEmpty ( ) )
return ERR_EMPTY_REGION ;
// Get info
2015-01-31 22:00:00 +08:00
QString name = tr ( " GbE region " ) ;
const GBE_MAC_ADDRESS * mac = ( const GBE_MAC_ADDRESS * ) gbe . constData ( ) ;
const GBE_VERSION * version = ( const GBE_VERSION * ) ( gbe . constData ( ) + GBE_VERSION_OFFSET ) ;
QString info = tr ( " Full size: %1h (%2) \n MAC: %3:%4:%5:%6:%7:%8 \n Version: %9.%10 " )
. hexarg ( gbe . size ( ) ) . arg ( gbe . size ( ) )
. hexarg2 ( mac - > vendor [ 0 ] , 2 )
. hexarg2 ( mac - > vendor [ 1 ] , 2 )
. hexarg2 ( mac - > vendor [ 2 ] , 2 )
. hexarg2 ( mac - > device [ 0 ] , 2 )
. hexarg2 ( mac - > device [ 1 ] , 2 )
. hexarg2 ( mac - > device [ 2 ] , 2 )
2014-05-03 19:21:03 +08:00
. arg ( version - > major )
. arg ( version - > minor ) ;
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Region , Subtypes : : GbeRegion , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , gbe , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : parseMeRegion ( const QByteArray & me , QModelIndex & index , const QModelIndex & parent , const UINT8 mode )
{
2015-01-31 22:00:00 +08:00
// Check sanity
2014-05-03 19:21:03 +08:00
if ( me . isEmpty ( ) )
return ERR_EMPTY_REGION ;
// Get info
2015-01-31 22:00:00 +08:00
QString name = tr ( " ME/TXE region " ) ;
QString info = tr ( " Full size: %1h (%2) " ) .
hexarg ( me . size ( ) ) . arg ( me . size ( ) ) ;
2014-05-03 19:21:03 +08:00
2015-01-31 22:00:00 +08:00
// Parse region
2014-07-09 15:20:13 +08:00
bool versionFound = true ;
2015-01-31 22:00:00 +08:00
bool emptyRegion = false ;
// Check for empty region
if ( me . count ( ) = = me . count ( ' \xFF ' ) | | me . count ( ) = = me . count ( ' \x00 ' ) ) {
// Further parsing not needed
emptyRegion = true ;
info + = tr ( " \n State: empty " ) ;
2014-05-03 19:21:03 +08:00
}
2015-01-31 22:00:00 +08:00
else {
// Search for new signature
INT32 versionOffset = me . indexOf ( ME_VERSION_SIGNATURE2 ) ;
if ( versionOffset < 0 ) { // New signature not found
// Search for old signature
versionOffset = me . indexOf ( ME_VERSION_SIGNATURE ) ;
if ( versionOffset < 0 ) {
info + = tr ( " \n Version: unknown " ) ;
versionFound = false ;
}
}
2014-07-09 15:20:13 +08:00
2015-01-31 22:00:00 +08:00
// Add version information
if ( versionFound ) {
const ME_VERSION * version = ( const ME_VERSION * ) ( me . constData ( ) + versionOffset ) ;
info + = tr ( " \n Version: %1.%2.%3.%4 " )
. arg ( version - > major )
. arg ( version - > minor )
. arg ( version - > bugfix )
. arg ( version - > build ) ;
}
2014-05-03 19:21:03 +08:00
}
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Region , Subtypes : : MeRegion , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , me , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
2015-01-31 22:00:00 +08:00
// Show messages
if ( emptyRegion ) {
msg ( tr ( " parseRegion: ME/TXE region is empty " ) , index ) ;
}
else if ( ! versionFound ) {
msg ( tr ( " parseRegion: ME/TXE region version is unknown, it can be damaged " ) , index ) ;
}
2014-07-25 07:59:51 +08:00
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : parsePdrRegion ( const QByteArray & pdr , QModelIndex & index , const QModelIndex & parent , const UINT8 mode )
{
2015-01-31 22:00:00 +08:00
// Check sanity
2014-05-03 19:21:03 +08:00
if ( pdr . isEmpty ( ) )
return ERR_EMPTY_REGION ;
// Get info
QString name = tr ( " PDR region " ) ;
2015-01-31 22:00:00 +08:00
QString info = tr ( " Full size: %1h (%2) " ) .
hexarg ( pdr . size ( ) ) . arg ( pdr . size ( ) ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Region , Subtypes : : PdrRegion , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , pdr , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
2014-07-25 07:59:51 +08:00
// Parse PDR region as BIOS space
UINT8 result = parseBios ( pdr , index ) ;
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME )
2014-07-25 07:59:51 +08:00
return result ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : parseBiosRegion ( const QByteArray & bios , QModelIndex & index , const QModelIndex & parent , const UINT8 mode )
{
if ( bios . isEmpty ( ) )
return ERR_EMPTY_REGION ;
// Get info
QString name = tr ( " BIOS region " ) ;
2015-01-31 22:00:00 +08:00
QString info = tr ( " Full size: %1h (%2) " ) .
hexarg ( bios . size ( ) ) . arg ( bios . size ( ) ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Region , Subtypes : : BiosRegion , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , bios , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
return parseBios ( bios , index ) ;
}
2015-01-31 22:00:00 +08:00
UINT32 FfsEngine : : getPaddingType ( const QByteArray & padding )
2014-10-30 11:56:37 +08:00
{
2014-11-18 23:01:20 +08:00
if ( padding . count ( ' \x00 ' ) = = padding . count ( ) )
2015-02-06 16:47:19 +08:00
return Subtypes : : ZeroPadding ;
2014-11-18 23:01:20 +08:00
if ( padding . count ( ' \xFF ' ) = = padding . count ( ) )
2015-02-06 16:47:19 +08:00
return Subtypes : : OnePadding ;
return Subtypes : : DataPadding ;
2014-10-30 11:56:37 +08:00
}
2014-05-03 19:21:03 +08:00
UINT8 FfsEngine : : parseBios ( const QByteArray & bios , const QModelIndex & parent )
{
// Search for first volume
UINT32 prevVolumeOffset ;
UINT8 result ;
2014-07-12 18:27:42 +08:00
2014-05-03 19:21:03 +08:00
result = findNextVolume ( bios , 0 , prevVolumeOffset ) ;
if ( result )
return result ;
// First volume is not at the beginning of BIOS space
QString name ;
QString info ;
if ( prevVolumeOffset > 0 ) {
// Get info
QByteArray padding = bios . left ( prevVolumeOffset ) ;
name = tr ( " Padding " ) ;
2015-01-31 22:00:00 +08:00
info = tr ( " Full size: %1h (%2) " )
. hexarg ( padding . size ( ) ) . arg ( padding . size ( ) ) ;
2014-11-18 23:01:20 +08:00
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
model - > addItem ( Types : : Padding , getPaddingType ( padding ) , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , padding , QByteArray ( ) , parent ) ;
2014-05-03 19:21:03 +08:00
}
// Search for and parse all volumes
UINT32 volumeOffset = prevVolumeOffset ;
UINT32 prevVolumeSize = 0 ;
UINT32 volumeSize = 0 ;
2014-11-09 05:24:53 +08:00
UINT32 bmVolumeSize = 0 ;
2014-05-03 19:21:03 +08:00
while ( true )
{
2014-07-12 18:27:42 +08:00
bool msgAlignmentBitsSet = false ;
bool msgUnaligned = false ;
bool msgUnknownRevision = false ;
2014-11-09 05:24:53 +08:00
bool msgSizeMismach = false ;
2014-07-12 18:27:42 +08:00
2014-05-03 19:21:03 +08:00
// Padding between volumes
if ( volumeOffset > prevVolumeOffset + prevVolumeSize ) {
UINT32 paddingSize = volumeOffset - prevVolumeOffset - prevVolumeSize ;
QByteArray padding = bios . mid ( prevVolumeOffset + prevVolumeSize , paddingSize ) ;
// Get info
name = tr ( " Padding " ) ;
2015-01-31 22:00:00 +08:00
info = tr ( " Full size: %1h (%2) " )
. hexarg ( padding . size ( ) ) . arg ( padding . size ( ) ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
model - > addItem ( Types : : Padding , getPaddingType ( padding ) , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , padding , QByteArray ( ) , parent ) ;
2014-05-03 19:21:03 +08:00
}
// Get volume size
2014-11-09 05:24:53 +08:00
result = getVolumeSize ( bios , volumeOffset , volumeSize , bmVolumeSize ) ;
2014-05-03 19:21:03 +08:00
if ( result )
return result ;
2014-11-09 05:24:53 +08:00
// Check reported size
if ( volumeSize ! = bmVolumeSize )
msgSizeMismach = true ;
2014-05-03 19:21:03 +08:00
//Check that volume is fully present in input
if ( volumeOffset + volumeSize > ( UINT32 ) bios . size ( ) ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseBios: one of volumes inside overlaps the end of data " ) , parent ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_VOLUME ;
}
// Check volume revision and alignment
2015-01-31 22:00:00 +08:00
const EFI_FIRMWARE_VOLUME_HEADER * volumeHeader = ( const EFI_FIRMWARE_VOLUME_HEADER * ) ( bios . constData ( ) + volumeOffset ) ;
2014-05-03 19:21:03 +08:00
UINT32 alignment ;
if ( volumeHeader - > Revision = = 1 ) {
// Acquire alignment capability bit
bool alignmentCap = volumeHeader - > Attributes & EFI_FVB_ALIGNMENT_CAP ;
if ( ! alignmentCap ) {
if ( volumeHeader - > Attributes & 0xFFFF0000 )
2014-07-12 18:27:42 +08:00
msgAlignmentBitsSet = true ;
2014-05-03 19:21:03 +08:00
}
}
else if ( volumeHeader - > Revision = = 2 ) {
// Acquire alignment
alignment = ( UINT32 ) pow ( 2.0 , ( int ) ( volumeHeader - > Attributes & EFI_FVB2_ALIGNMENT ) > > 16 ) ;
// Check alignment
2014-07-12 18:27:42 +08:00
if ( volumeOffset % alignment )
msgUnaligned = true ;
2014-05-03 19:21:03 +08:00
}
else
2014-07-12 18:27:42 +08:00
msgUnknownRevision = true ;
2014-05-03 19:21:03 +08:00
// Parse volume
QModelIndex index ;
UINT8 result = parseVolume ( bios . mid ( volumeOffset , volumeSize ) , index , parent ) ;
if ( result )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseBios: volume parsing failed with error \" %1 \" " ) . arg ( errorMessage ( result ) ) , parent ) ;
2014-07-12 18:27:42 +08:00
// Show messages
if ( msgAlignmentBitsSet )
2015-02-06 16:47:19 +08:00
msg ( " parseBios: alignment bits set on volume without alignment capability " , index ) ;
2014-07-12 18:27:42 +08:00
if ( msgUnaligned )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseBios: unaligned revision 2 volume " ) , index ) ;
2014-07-12 18:27:42 +08:00
if ( msgUnknownRevision )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseBios: unknown volume revision %1 " ) . arg ( volumeHeader - > Revision ) , index ) ;
2014-11-09 05:24:53 +08:00
if ( msgSizeMismach )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseBios: volume size stored in header %1h (%2) differs from calculated using block map %3h (%4) " )
. hexarg ( volumeSize ) . arg ( volumeSize )
. hexarg ( bmVolumeSize ) . arg ( bmVolumeSize ) ,
index ) ;
2014-05-03 19:21:03 +08:00
// Go to next volume
prevVolumeOffset = volumeOffset ;
prevVolumeSize = volumeSize ;
result = findNextVolume ( bios , volumeOffset + prevVolumeSize , volumeOffset ) ;
if ( result ) {
UINT32 endPaddingSize = bios . size ( ) - prevVolumeOffset - prevVolumeSize ;
// Padding at the end of BIOS space
if ( endPaddingSize > 0 ) {
QByteArray padding = bios . right ( endPaddingSize ) ;
// Get info
name = tr ( " Padding " ) ;
2015-01-31 22:00:00 +08:00
info = tr ( " Full size: %1h (%2) " )
. hexarg ( padding . size ( ) ) . arg ( padding . size ( ) ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
model - > addItem ( Types : : Padding , getPaddingType ( padding ) , COMPRESSION_ALGORITHM_NONE , name , " " , info , QByteArray ( ) , padding , QByteArray ( ) , parent ) ;
2014-05-03 19:21:03 +08:00
}
break ;
}
}
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : findNextVolume ( const QByteArray & bios , UINT32 volumeOffset , UINT32 & nextVolumeOffset )
{
int nextIndex = bios . indexOf ( EFI_FV_SIGNATURE , volumeOffset ) ;
if ( nextIndex < EFI_FV_SIGNATURE_OFFSET ) {
return ERR_VOLUMES_NOT_FOUND ;
}
nextVolumeOffset = nextIndex - EFI_FV_SIGNATURE_OFFSET ;
return ERR_SUCCESS ;
}
2014-11-09 05:24:53 +08:00
UINT8 FfsEngine : : getVolumeSize ( const QByteArray & bios , UINT32 volumeOffset , UINT32 & volumeSize , UINT32 & bmVolumeSize )
2014-05-03 19:21:03 +08:00
{
// Populate volume header
2015-01-31 22:00:00 +08:00
const EFI_FIRMWARE_VOLUME_HEADER * volumeHeader = ( const EFI_FIRMWARE_VOLUME_HEADER * ) ( bios . constData ( ) + volumeOffset ) ;
2014-05-03 19:21:03 +08:00
// Check volume signature
if ( QByteArray ( ( const char * ) & volumeHeader - > Signature , sizeof ( volumeHeader - > Signature ) ) ! = EFI_FV_SIGNATURE )
return ERR_INVALID_VOLUME ;
// Calculate volume size using BlockMap
2015-01-31 22:00:00 +08:00
const EFI_FV_BLOCK_MAP_ENTRY * entry = ( const EFI_FV_BLOCK_MAP_ENTRY * ) ( bios . constData ( ) + volumeOffset + sizeof ( EFI_FIRMWARE_VOLUME_HEADER ) ) ;
2014-11-09 05:24:53 +08:00
UINT32 calcVolumeSize = 0 ;
2014-05-03 19:21:03 +08:00
while ( entry - > NumBlocks ! = 0 & & entry - > Length ! = 0 ) {
if ( ( void * ) entry > bios . constData ( ) + bios . size ( ) )
return ERR_INVALID_VOLUME ;
2014-11-09 05:24:53 +08:00
calcVolumeSize + = entry - > NumBlocks * entry - > Length ;
2014-05-03 19:21:03 +08:00
entry + = 1 ;
}
2014-11-09 05:24:53 +08:00
volumeSize = volumeHeader - > FvLength ;
bmVolumeSize = calcVolumeSize ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : parseVolume ( const QByteArray & volume , QModelIndex & index , const QModelIndex & parent , const UINT8 mode )
{
// Populate volume header
2015-01-31 22:00:00 +08:00
const EFI_FIRMWARE_VOLUME_HEADER * volumeHeader = ( const EFI_FIRMWARE_VOLUME_HEADER * ) ( volume . constData ( ) ) ;
2014-05-03 19:21:03 +08:00
// Calculate volume header size
UINT32 headerSize ;
if ( volumeHeader - > Revision > 1 & & volumeHeader - > ExtHeaderOffset ) {
2015-01-31 22:00:00 +08:00
const EFI_FIRMWARE_VOLUME_EXT_HEADER * extendedHeader = ( const EFI_FIRMWARE_VOLUME_EXT_HEADER * ) ( volume . constData ( ) + volumeHeader - > ExtHeaderOffset ) ;
2014-05-03 19:21:03 +08:00
headerSize = volumeHeader - > ExtHeaderOffset + extendedHeader - > ExtHeaderSize ;
}
2014-07-25 07:59:51 +08:00
else
2014-05-03 19:21:03 +08:00
headerSize = volumeHeader - > HeaderLength ;
2014-07-25 07:59:51 +08:00
2014-05-03 19:21:03 +08:00
// Sanity check after some new crazy MSI images
headerSize = ALIGN8 ( headerSize ) ;
// Check for volume structure to be known
2015-02-06 16:47:19 +08:00
bool volumeIsUnknown = true ;
2015-02-14 04:19:02 +08:00
/*UINT8 volumeFfsVersion = 0;*/
2015-01-31 22:00:00 +08:00
// Check for FFS v2 volume
if ( FFSv2Volumes . contains ( QByteArray : : fromRawData ( ( const char * ) volumeHeader - > FileSystemGuid . Data , sizeof ( EFI_GUID ) ) ) ) {
2015-02-06 16:47:19 +08:00
volumeIsUnknown = false ;
2015-02-14 04:19:02 +08:00
/*volumeFfsVersion = 2;*/
2014-05-03 19:21:03 +08:00
}
2015-02-13 03:51:23 +08:00
// Check for FFS v3 volume
/*if (FFSv3Volumes.contains(QByteArray::fromRawData((const char*)volumeHeader->FileSystemGuid.Data, sizeof(EFI_GUID)))) {
volumeIsUnknown = false ;
volumeFfsVersion = 3 ;
} */
2014-05-03 19:21:03 +08:00
// Check attributes
// Determine value of empty byte
char empty = volumeHeader - > Attributes & EFI_FVB_ERASE_POLARITY ? ' \xFF ' : ' \x00 ' ;
// Get volume size
UINT32 volumeSize ;
2014-11-09 05:24:53 +08:00
UINT32 bmVolumeSize ;
2014-05-03 19:21:03 +08:00
2015-01-26 06:55:05 +08:00
UINT8 result = getVolumeSize ( volume , 0 , volumeSize , bmVolumeSize ) ;
2014-05-03 19:21:03 +08:00
if ( result )
return result ;
2015-01-26 06:55:05 +08:00
// Check for Apple CRC32 in ZeroVector
2015-02-06 16:47:19 +08:00
bool volumeHasZVCRC = false ;
2015-01-26 06:55:05 +08:00
UINT32 crc32FromZeroVector = * ( UINT32 * ) ( volume . constData ( ) + 8 ) ;
if ( crc32FromZeroVector ! = 0 ) {
// Calculate CRC32 of the volume body
2015-01-31 22:00:00 +08:00
UINT32 crc = crc32 ( 0 , ( const UINT8 * ) ( volume . constData ( ) + volumeHeader - > HeaderLength ) , volumeSize - volumeHeader - > HeaderLength ) ;
2015-01-26 06:55:05 +08:00
if ( crc = = crc32FromZeroVector ) {
2015-02-06 16:47:19 +08:00
volumeHasZVCRC = true ;
2015-01-26 06:55:05 +08:00
}
}
2014-05-03 19:21:03 +08:00
// Check header checksum by recalculating it
2015-01-31 22:00:00 +08:00
bool msgInvalidChecksum = false ;
2015-02-06 16:47:19 +08:00
if ( ! volumeIsUnknown & & calculateChecksum16 ( ( const UINT16 * ) volumeHeader , volumeHeader - > HeaderLength ) )
2014-07-12 18:27:42 +08:00
msgInvalidChecksum = true ;
2014-05-03 19:21:03 +08:00
// Get info
QString name = guidToQString ( volumeHeader - > FileSystemGuid ) ;
2015-01-31 22:00:00 +08:00
QString info = tr ( " ZeroVector: \n %1 %2 %3 %4 %5 %6 %7 %8 \n %9 %10 %11 %12 %13 %14 %15 %16 \n FileSystem GUID: %17 \n Full size: %18h (%19) \n "
" Header size: %20h (%21) \n Body size: %22h (%23) \n Revision: %24 \n Attributes: %25h \n Erase polarity: %26 " )
. hexarg2 ( volumeHeader - > ZeroVector [ 0 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 1 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 2 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 3 ] , 2 )
. hexarg2 ( volumeHeader - > ZeroVector [ 4 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 5 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 6 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 7 ] , 2 )
. hexarg2 ( volumeHeader - > ZeroVector [ 8 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 9 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 10 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 11 ] , 2 )
. hexarg2 ( volumeHeader - > ZeroVector [ 12 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 13 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 14 ] , 2 ) . hexarg2 ( volumeHeader - > ZeroVector [ 15 ] , 2 )
2014-05-03 19:21:03 +08:00
. arg ( guidToQString ( volumeHeader - > FileSystemGuid ) )
2015-01-31 22:00:00 +08:00
. hexarg ( volumeSize ) . arg ( volumeSize )
. hexarg ( headerSize ) . arg ( headerSize )
. hexarg ( volumeSize - headerSize ) . arg ( volumeSize - headerSize )
2014-05-03 19:21:03 +08:00
. arg ( volumeHeader - > Revision )
2015-01-31 22:00:00 +08:00
. hexarg2 ( volumeHeader - > Attributes , 8 )
. arg ( empty ? " 1 " : " 0 " ) ;
2015-01-26 06:55:05 +08:00
// Apple CRC32 volume
2015-02-06 16:47:19 +08:00
if ( volumeHasZVCRC ) {
2015-01-26 06:55:05 +08:00
info + = tr ( " \n CRC32 in ZeroVector: valid " ) ;
}
2014-05-03 19:21:03 +08:00
// Extended header present
if ( volumeHeader - > Revision > 1 & & volumeHeader - > ExtHeaderOffset ) {
2015-01-31 22:00:00 +08:00
const EFI_FIRMWARE_VOLUME_EXT_HEADER * extendedHeader = ( const EFI_FIRMWARE_VOLUME_EXT_HEADER * ) ( volume . constData ( ) + volumeHeader - > ExtHeaderOffset ) ;
info + = tr ( " \n Extended header size: %1h (%2) \n Volume GUID: %3 " )
. hexarg ( extendedHeader - > ExtHeaderSize ) . arg ( extendedHeader - > ExtHeaderSize )
2014-05-03 19:21:03 +08:00
. arg ( guidToQString ( extendedHeader - > FvName ) ) ;
}
2015-02-06 16:47:19 +08:00
// Construct parsing data structure
QByteArray parsingData ( sizeof ( PARSING_DATA ) , 0 ) ;
PARSING_DATA * pdata = ( PARSING_DATA * ) parsingData . data ( ) ;
2015-02-07 00:46:26 +08:00
pdata - > Type = VolumeParsingData ;
2015-02-06 16:47:19 +08:00
pdata - > Data . Volume . HasZeroVectorCRC = volumeHasZVCRC ;
// Add text
QString text ;
if ( volumeHasZVCRC )
text + = tr ( " ZeroVectorCRC " ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
QByteArray header = volume . left ( headerSize ) ;
QByteArray body = volume . mid ( headerSize , volumeSize - headerSize ) ;
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Volume , volumeIsUnknown ? Subtypes : : UnknownVolume : Subtypes : : Ffs2Volume , COMPRESSION_ALGORITHM_NONE , name , text , info , header , body , parsingData , parent , mode ) ;
2014-05-03 19:21:03 +08:00
2014-07-12 18:27:42 +08:00
// Show messages
2015-02-06 16:47:19 +08:00
if ( volumeIsUnknown ) {
msg ( tr ( " parseVolume: unknown file system %1 " ) . arg ( guidToQString ( volumeHeader - > FileSystemGuid ) ) , index ) ;
2015-01-31 22:00:00 +08:00
// Do not parse unknown volumes
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
2015-01-31 22:00:00 +08:00
}
if ( msgInvalidChecksum ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseVolume: volume header checksum is invalid " ) , index ) ;
2015-01-31 22:00:00 +08:00
}
2014-05-03 19:21:03 +08:00
// Search for and parse all files
UINT32 fileOffset = headerSize ;
UINT32 fileSize ;
QQueue < QByteArray > files ;
2014-07-12 18:27:42 +08:00
while ( fileOffset < volumeSize ) {
bool msgUnalignedFile = false ;
bool msgDuplicateGuid = false ;
2014-05-03 19:21:03 +08:00
result = getFileSize ( volume , fileOffset , fileSize ) ;
if ( result )
return result ;
// Check file size to be at least size of EFI_FFS_FILE_HEADER
if ( fileSize < sizeof ( EFI_FFS_FILE_HEADER ) ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseVolume: volume has FFS file with invalid size " ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FILE ;
}
QByteArray file = volume . mid ( fileOffset , fileSize ) ;
QByteArray header = file . left ( sizeof ( EFI_FFS_FILE_HEADER ) ) ;
// If we are at empty space in the end of volume
2014-11-18 23:01:20 +08:00
if ( header . count ( empty ) = = header . size ( ) ) {
// Check free space to be actually free
2015-02-06 16:47:19 +08:00
QByteArray freeSpace = volume . mid ( fileOffset ) ;
if ( freeSpace . count ( empty ) ! = freeSpace . count ( ) ) {
// Search for the first non-empty byte
UINT32 i ;
UINT32 size = freeSpace . size ( ) ;
const CHAR8 * current = freeSpace . constData ( ) ;
for ( i = 0 ; i < size ; i + + ) {
if ( * current + + ! = empty )
break ;
}
// Align found index to file alignment
// It must be possible because minimum 16 bytes of empty were found before
if ( i ! = ALIGN8 ( i ) )
i = ALIGN8 ( i ) - 8 ;
// 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 , QByteArray ( ) , index , mode ) ;
}
// ... and all bytes after as a padding
QByteArray padding = freeSpace . mid ( i ) ;
2015-02-13 04:15:11 +08:00
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 , QByteArray ( ) , index , mode ) ;
msg ( tr ( " parseVolume: non-UEFI data found in volume's free space " ) , dataIndex ) ;
2015-02-06 16:47:19 +08:00
}
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 , QByteArray ( ) , index , mode ) ;
}
2014-11-18 23:01:20 +08:00
break ; // Exit from loop
}
2014-05-03 19:21:03 +08:00
// Check file alignment
2015-01-31 22:00:00 +08:00
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) header . constData ( ) ;
2014-05-03 19:21:03 +08:00
UINT8 alignmentPower = ffsAlignmentTable [ ( fileHeader - > Attributes & FFS_ATTRIB_DATA_ALIGNMENT ) > > 3 ] ;
UINT32 alignment = ( UINT32 ) pow ( 2.0 , alignmentPower ) ;
2014-07-12 18:27:42 +08:00
if ( ( fileOffset + sizeof ( EFI_FFS_FILE_HEADER ) ) % alignment )
msgUnalignedFile = true ;
2014-05-03 19:21:03 +08:00
// Check file GUID
if ( fileHeader - > Type ! = EFI_FV_FILETYPE_PAD & & files . indexOf ( header . left ( sizeof ( EFI_GUID ) ) ) ! = - 1 )
2014-07-12 18:27:42 +08:00
msgDuplicateGuid = true ;
2014-05-03 19:21:03 +08:00
// Add file GUID to queue
files . enqueue ( header . left ( sizeof ( EFI_GUID ) ) ) ;
// Parse file
QModelIndex fileIndex ;
result = parseFile ( file , fileIndex , empty = = ' \xFF ' ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE , index ) ;
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME )
2014-10-30 11:56:37 +08:00
msg ( tr ( " parseVolume: FFS file parsing failed with error \" %1 \" " ) . arg ( errorMessage ( result ) ) , index ) ;
2014-07-12 18:27:42 +08:00
2015-02-06 16:47:19 +08:00
// Construct parsing data structure
QByteArray parsingData ( sizeof ( PARSING_DATA ) , 0 ) ;
PARSING_DATA * pdata = ( PARSING_DATA * ) parsingData . data ( ) ;
2015-02-07 00:46:26 +08:00
pdata - > Type = FileParsingData ;
2015-02-06 16:47:19 +08:00
pdata - > Data . File . Offset = fileOffset ;
model - > setParsingData ( fileIndex , parsingData ) ;
2014-07-12 18:27:42 +08:00
// Show messages
if ( msgUnalignedFile )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseVolume: unaligned file %1 " ) . arg ( guidToQString ( fileHeader - > Name ) ) , fileIndex ) ;
2014-07-12 18:27:42 +08:00
if ( msgDuplicateGuid )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseVolume: file with duplicate GUID %1 " ) . arg ( guidToQString ( fileHeader - > Name ) ) , fileIndex ) ;
2014-05-03 19:21:03 +08:00
// Move to next file
fileOffset + = fileSize ;
fileOffset = ALIGN8 ( fileOffset ) ;
}
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : getFileSize ( const QByteArray & volume , const UINT32 fileOffset , UINT32 & fileSize )
{
2015-01-31 22:00:00 +08:00
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) ( volume . constData ( ) + fileOffset ) ;
2014-05-03 19:21:03 +08:00
fileSize = uint24ToUint32 ( fileHeader - > Size ) ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : parseFile ( const QByteArray & file , QModelIndex & index , const UINT8 erasePolarity , const QModelIndex & parent , const UINT8 mode )
{
2014-11-18 23:01:20 +08:00
bool msgInvalidHeaderChecksum = false ;
bool msgInvalidDataChecksum = false ;
2014-07-12 18:27:42 +08:00
bool msgInvalidTailValue = false ;
bool msgInvalidType = false ;
2014-05-03 19:21:03 +08:00
// Populate file header
2015-01-31 22:00:00 +08:00
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) file . constData ( ) ;
2014-05-03 19:21:03 +08:00
// Check file state
// Construct empty byte for this file
char empty = erasePolarity ? ' \xFF ' : ' \x00 ' ;
// Check header checksum
QByteArray header = file . left ( sizeof ( EFI_FFS_FILE_HEADER ) ) ;
QByteArray tempHeader = header ;
EFI_FFS_FILE_HEADER * tempFileHeader = ( EFI_FFS_FILE_HEADER * ) ( tempHeader . data ( ) ) ;
tempFileHeader - > IntegrityCheck . Checksum . Header = 0 ;
tempFileHeader - > IntegrityCheck . Checksum . File = 0 ;
2015-01-31 22:00:00 +08:00
UINT8 calculated = calculateChecksum8 ( ( const UINT8 * ) tempFileHeader , sizeof ( EFI_FFS_FILE_HEADER ) - 1 ) ;
2014-11-18 23:01:20 +08:00
if ( fileHeader - > IntegrityCheck . Checksum . Header ! = calculated )
msgInvalidHeaderChecksum = true ;
2014-05-03 19:21:03 +08:00
// Check data checksum
// Data checksum must be calculated
if ( fileHeader - > Attributes & FFS_ATTRIB_CHECKSUM ) {
UINT32 bufferSize = file . size ( ) - sizeof ( EFI_FFS_FILE_HEADER ) ;
// Exclude file tail from data checksum calculation
if ( fileHeader - > Attributes & FFS_ATTRIB_TAIL_PRESENT )
bufferSize - = sizeof ( UINT16 ) ;
2015-01-31 22:00:00 +08:00
calculated = calculateChecksum8 ( ( const UINT8 * ) ( file . constData ( ) + sizeof ( EFI_FFS_FILE_HEADER ) ) , bufferSize ) ;
2014-07-12 18:27:42 +08:00
if ( fileHeader - > IntegrityCheck . Checksum . File ! = calculated )
msgInvalidDataChecksum = true ;
2014-05-03 19:21:03 +08:00
}
// Data checksum must be one of predefined values
2014-07-12 18:27:42 +08:00
else if ( fileHeader - > IntegrityCheck . Checksum . File ! = FFS_FIXED_CHECKSUM & & fileHeader - > IntegrityCheck . Checksum . File ! = FFS_FIXED_CHECKSUM2 )
msgInvalidDataChecksum = true ;
2014-05-03 19:21:03 +08:00
// Get file body
QByteArray body = file . right ( file . size ( ) - sizeof ( EFI_FFS_FILE_HEADER ) ) ;
// Check for file tail presence
QByteArray tail ;
if ( fileHeader - > Attributes & FFS_ATTRIB_TAIL_PRESENT )
{
//Check file tail;
tail = body . right ( sizeof ( UINT16 ) ) ;
UINT16 tailValue = * ( UINT16 * ) tail . constData ( ) ;
if ( fileHeader - > IntegrityCheck . TailReference ! = ( UINT16 ) ~ tailValue )
2014-07-12 18:27:42 +08:00
msgInvalidTailValue = true ;
2014-05-03 19:21:03 +08:00
// Remove tail from file body
body = body . left ( body . size ( ) - sizeof ( UINT16 ) ) ;
}
// Parse current file by default
bool parseCurrentFile = true ;
bool parseAsBios = false ;
// Check file type
switch ( fileHeader - > Type )
{
case EFI_FV_FILETYPE_ALL :
parseAsBios = true ;
break ;
case EFI_FV_FILETYPE_RAW :
parseAsBios = true ;
break ;
case EFI_FV_FILETYPE_FREEFORM :
break ;
case EFI_FV_FILETYPE_SECURITY_CORE :
break ;
case EFI_FV_FILETYPE_PEI_CORE :
break ;
case EFI_FV_FILETYPE_DXE_CORE :
break ;
case EFI_FV_FILETYPE_PEIM :
break ;
case EFI_FV_FILETYPE_DRIVER :
break ;
case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER :
break ;
case EFI_FV_FILETYPE_APPLICATION :
break ;
case EFI_FV_FILETYPE_SMM :
break ;
case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE :
break ;
case EFI_FV_FILETYPE_COMBINED_SMM_DXE :
break ;
case EFI_FV_FILETYPE_SMM_CORE :
break ;
case EFI_FV_FILETYPE_PAD :
break ;
default :
2014-07-12 18:27:42 +08:00
msgInvalidType = true ;
2014-05-03 19:21:03 +08:00
parseCurrentFile = false ;
} ;
// Check for empty file
2015-02-06 16:47:19 +08:00
bool parseAsNonEmptyPadFile = false ;
2014-05-03 19:21:03 +08:00
if ( body . count ( empty ) = = body . size ( ) ) {
// No need to parse empty files
parseCurrentFile = false ;
}
2014-11-18 23:01:20 +08:00
// Check for non-empty pad file
else if ( fileHeader - > Type = = EFI_FV_FILETYPE_PAD ) {
2015-02-06 16:47:19 +08:00
parseAsNonEmptyPadFile = true ;
2014-11-18 23:01:20 +08:00
}
2014-05-03 19:21:03 +08:00
// Get info
QString name ;
QString info ;
if ( fileHeader - > Type ! = EFI_FV_FILETYPE_PAD )
name = guidToQString ( fileHeader - > Name ) ;
2015-02-06 16:47:19 +08:00
else
name = parseAsNonEmptyPadFile ? tr ( " Non-empty pad-file " ) : tr ( " Pad-file " ) ;
2015-01-31 22:00:00 +08:00
info = tr ( " File GUID: %1 \n Type: %2h \n Attributes: %3h \n Full size: %4h (%5) \n Header size: %6h (%7) \n Body size: %8h (%9) \n State: %10h " )
2014-05-03 19:21:03 +08:00
. arg ( guidToQString ( fileHeader - > Name ) )
2015-01-31 22:00:00 +08:00
. hexarg2 ( fileHeader - > Type , 2 )
. hexarg2 ( fileHeader - > Attributes , 2 )
. hexarg ( header . size ( ) + body . size ( ) ) . arg ( header . size ( ) + body . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) )
. hexarg2 ( fileHeader - > State , 2 ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : File , fileHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
2014-07-12 18:27:42 +08:00
// Show messages
2014-11-18 23:01:20 +08:00
if ( msgInvalidHeaderChecksum )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseFile: invalid header checksum " ) , index ) ;
2014-07-12 18:27:42 +08:00
if ( msgInvalidDataChecksum )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseFile: invalid data checksum " ) , index ) ;
2014-07-12 18:27:42 +08:00
if ( msgInvalidTailValue )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseFile: invalid tail value " ) , index ) ;
2014-07-12 18:27:42 +08:00
if ( msgInvalidType )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseFile: unknown file type %1h " ) . arg ( fileHeader - > Type , 2 ) , index ) ;
// No parsing needed
2014-05-03 19:21:03 +08:00
if ( ! parseCurrentFile )
return ERR_SUCCESS ;
2015-02-06 16:47:19 +08:00
// Parse non-empty pad file
if ( parseAsNonEmptyPadFile ) {
// Search for the first non-empty byte
UINT32 i ;
UINT32 size = body . size ( ) ;
const CHAR8 * current = body . constData ( ) ;
for ( i = 0 ; i < size ; i + + ) {
if ( * current + + ! = empty )
break ;
}
// Add all bytes before as free space...
if ( i > 0 ) {
QByteArray free = body . left ( i ) ;
model - > addItem ( Types : : FreeSpace , 0 , COMPRESSION_ALGORITHM_NONE , tr ( " Free space " ) , " " , tr ( " Full size: %1h (%2) " ) . hexarg ( free . size ( ) ) . arg ( free . size ( ) ) , QByteArray ( ) , free , QByteArray ( ) , index , mode ) ;
}
// ... and all bytes after as a padding
QByteArray padding = body . mid ( i ) ;
2015-02-13 03:51:23 +08:00
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 , QByteArray ( ) , index , mode ) ;
// Show message
msg ( tr ( " parseFile: non-empty pad-file contents will be destroyed after volume modifications " ) , dataIndex ) ;
2015-02-06 16:47:19 +08:00
return ERR_SUCCESS ;
}
2014-05-03 19:21:03 +08:00
// Parse file as BIOS space
UINT8 result ;
if ( parseAsBios ) {
result = parseBios ( body , index ) ;
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseFile: parsing file as BIOS failed with error \" %1 \" " ) . arg ( errorMessage ( result ) ) , index ) ;
2014-07-12 18:27:42 +08:00
return result ;
2014-05-03 19:21:03 +08:00
}
// Parse sections
result = parseSections ( body , index ) ;
if ( result )
return result ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : getSectionSize ( const QByteArray & file , const UINT32 sectionOffset , UINT32 & sectionSize )
{
2015-01-31 22:00:00 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( file . constData ( ) + sectionOffset ) ;
2014-05-03 19:21:03 +08:00
sectionSize = uint24ToUint32 ( sectionHeader - > Size ) ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : parseSections ( const QByteArray & body , const QModelIndex & parent )
{
// Search for and parse all sections
UINT32 sectionOffset = 0 ;
UINT32 sectionSize ;
UINT32 bodySize = body . size ( ) ;
UINT8 result ;
while ( true ) {
// Get section size
result = getSectionSize ( body , sectionOffset , sectionSize ) ;
if ( result )
return result ;
// Parse section
QModelIndex sectionIndex ;
result = parseSection ( body . mid ( sectionOffset , sectionSize ) , sectionIndex , parent ) ;
if ( result )
return result ;
// Move to next section
sectionOffset + = sectionSize ;
sectionOffset = ALIGN4 ( sectionOffset ) ;
// Exit from loop if no sections left
if ( sectionOffset > = bodySize )
break ;
}
return ERR_SUCCESS ;
}
2014-11-02 18:27:54 +08:00
void FfsEngine : : parseAprioriRawSection ( const QByteArray & body , QString & parsed )
{
parsed . clear ( ) ;
UINT32 count = body . size ( ) / sizeof ( EFI_GUID ) ;
if ( count > 0 ) {
for ( UINT32 i = 0 ; i < count ; i + + ) {
2015-01-31 22:00:00 +08:00
const EFI_GUID * guid = ( const EFI_GUID * ) body . constData ( ) + i ;
2014-11-02 18:27:54 +08:00
parsed + = tr ( " \n %1 " ) . arg ( guidToQString ( * guid ) ) ;
}
}
}
UINT8 FfsEngine : : parseDepexSection ( const QByteArray & body , QString & parsed )
{
parsed . clear ( ) ;
// Check data to be present
if ( ! body . size ( ) )
return ERR_INVALID_PARAMETER ;
2015-01-31 22:00:00 +08:00
const EFI_GUID * guid ;
const UINT8 * current = ( const UINT8 * ) body . constData ( ) ;
2014-11-02 18:27:54 +08:00
// Special cases of first opcode
switch ( * current ) {
case EFI_DEP_BEFORE :
if ( body . size ( ) ! = 2 * EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) )
return ERR_DEPEX_PARSE_FAILED ;
2015-01-31 22:00:00 +08:00
guid = ( const EFI_GUID * ) ( current + EFI_DEP_OPCODE_SIZE ) ;
2014-11-02 18:27:54 +08:00
parsed + = tr ( " \n BEFORE %1 " ) . arg ( guidToQString ( * guid ) ) ;
current + = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ;
if ( * current ! = EFI_DEP_END )
return ERR_DEPEX_PARSE_FAILED ;
return ERR_SUCCESS ;
case EFI_DEP_AFTER :
if ( body . size ( ) ! = 2 * EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) )
return ERR_DEPEX_PARSE_FAILED ;
2015-01-31 22:00:00 +08:00
guid = ( const EFI_GUID * ) ( current + EFI_DEP_OPCODE_SIZE ) ;
2014-11-02 18:27:54 +08:00
parsed + = tr ( " \n AFTER %1 " ) . arg ( guidToQString ( * guid ) ) ;
current + = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ;
if ( * current ! = EFI_DEP_END )
return ERR_DEPEX_PARSE_FAILED ;
return ERR_SUCCESS ;
case EFI_DEP_SOR :
if ( body . size ( ) < = 2 * EFI_DEP_OPCODE_SIZE ) {
return ERR_DEPEX_PARSE_FAILED ;
}
parsed + = tr ( " \n SOR " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
}
// Parse the rest of depex
2015-01-31 22:00:00 +08:00
while ( current - ( const UINT8 * ) body . constData ( ) < body . size ( ) ) {
2014-11-02 18:27:54 +08:00
switch ( * current ) {
case EFI_DEP_BEFORE :
case EFI_DEP_AFTER :
case EFI_DEP_SOR :
return ERR_DEPEX_PARSE_FAILED ;
case EFI_DEP_PUSH :
// Check that the rest of depex has correct size
2015-01-31 22:00:00 +08:00
if ( ( UINT32 ) body . size ( ) - ( UINT32 ) ( current - ( const UINT8 * ) body . constData ( ) ) < = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ) {
2014-11-02 18:27:54 +08:00
parsed . clear ( ) ;
return ERR_DEPEX_PARSE_FAILED ;
}
2015-01-31 22:00:00 +08:00
guid = ( const EFI_GUID * ) ( current + EFI_DEP_OPCODE_SIZE ) ;
2014-11-02 18:27:54 +08:00
parsed + = tr ( " \n PUSH %1 " ) . arg ( guidToQString ( * guid ) ) ;
current + = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ;
break ;
case EFI_DEP_AND :
parsed + = tr ( " \n AND " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_OR :
parsed + = tr ( " \n OR " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_NOT :
parsed + = tr ( " \n NOT " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_TRUE :
parsed + = tr ( " \n TRUE " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_FALSE :
parsed + = tr ( " \n FALSE " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_END :
parsed + = tr ( " \n END " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
// Check that END is the last opcode
2015-01-31 22:00:00 +08:00
if ( current - ( const UINT8 * ) body . constData ( ) < body . size ( ) ) {
2014-11-02 18:27:54 +08:00
parsed . clear ( ) ;
return ERR_DEPEX_PARSE_FAILED ;
}
break ;
2015-02-18 06:46:15 +08:00
default :
return ERR_DEPEX_PARSE_FAILED ;
break ;
2014-11-02 18:27:54 +08:00
}
}
return ERR_SUCCESS ;
}
2014-05-03 19:21:03 +08:00
UINT8 FfsEngine : : parseSection ( const QByteArray & section , QModelIndex & index , const QModelIndex & parent , const UINT8 mode )
{
2015-01-31 22:00:00 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
2014-05-03 19:21:03 +08:00
QString name = sectionTypeToQString ( sectionHeader - > Type ) + tr ( " section " ) ;
QString info ;
QByteArray header ;
QByteArray body ;
UINT32 headerSize ;
UINT8 result ;
switch ( sectionHeader - > Type ) {
2015-01-31 22:00:00 +08:00
// Encapsulated sections
2014-05-03 19:21:03 +08:00
case EFI_SECTION_COMPRESSION :
{
bool parseCurrentSection = true ;
QByteArray decompressed ;
UINT8 algorithm ;
2015-01-31 22:00:00 +08:00
const EFI_COMPRESSION_SECTION * compressedSectionHeader = ( const EFI_COMPRESSION_SECTION * ) sectionHeader ;
2014-05-03 19:21:03 +08:00
header = section . left ( sizeof ( EFI_COMPRESSION_SECTION ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( EFI_COMPRESSION_SECTION ) ) ;
2014-05-03 19:21:03 +08:00
algorithm = COMPRESSION_ALGORITHM_UNKNOWN ;
// Decompress section
result = decompress ( body , compressedSectionHeader - > CompressionType , decompressed , & algorithm ) ;
2014-07-12 18:27:42 +08:00
if ( result )
2014-05-03 19:21:03 +08:00
parseCurrentSection = false ;
2014-07-25 07:59:51 +08:00
2014-05-03 19:21:03 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) \n Compression type: %8 \n Decompressed size: %9h (%10) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) )
2014-05-03 19:21:03 +08:00
. arg ( compressionTypeToQString ( algorithm ) )
2015-01-31 22:00:00 +08:00
. hexarg ( compressedSectionHeader - > UncompressedLength ) . arg ( compressedSectionHeader - > UncompressedLength ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , algorithm , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
2014-07-12 18:27:42 +08:00
// Show message
2014-07-25 07:59:51 +08:00
if ( ! parseCurrentSection )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseSection: decompression failed with error \" %1 \" " ) . arg ( errorMessage ( result ) ) , index ) ;
2014-07-12 18:27:42 +08:00
else { // Parse decompressed data
2014-05-03 19:21:03 +08:00
result = parseSections ( decompressed , index ) ;
if ( result )
return result ;
}
2015-01-31 22:00:00 +08:00
} break ;
2014-05-03 19:21:03 +08:00
case EFI_SECTION_GUID_DEFINED :
{
bool parseCurrentSection = true ;
2014-07-12 18:27:42 +08:00
bool msgUnknownGuid = false ;
bool msgInvalidCrc = false ;
bool msgUnknownAuth = false ;
2015-02-13 03:51:23 +08:00
bool msgSigned = false ;
bool msgUnknownSignature = false ;
bool msgUnknownUefiGuidSignature = false ;
2014-07-12 18:27:42 +08:00
2015-01-31 22:00:00 +08:00
const EFI_GUID_DEFINED_SECTION * guidDefinedSectionHeader ;
2014-05-03 19:21:03 +08:00
header = section . left ( sizeof ( EFI_GUID_DEFINED_SECTION ) ) ;
2015-01-31 22:00:00 +08:00
guidDefinedSectionHeader = ( const EFI_GUID_DEFINED_SECTION * ) ( header . constData ( ) ) ;
2014-05-03 19:21:03 +08:00
header = section . left ( guidDefinedSectionHeader - > DataOffset ) ;
2015-01-31 22:00:00 +08:00
guidDefinedSectionHeader = ( const EFI_GUID_DEFINED_SECTION * ) ( header . constData ( ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( guidDefinedSectionHeader - > DataOffset ) ;
2015-01-31 22:00:00 +08:00
QByteArray processed = body ;
2014-05-03 19:21:03 +08:00
// Get info
name = guidToQString ( guidDefinedSectionHeader - > SectionDefinitionGuid ) ;
2015-02-06 16:47:19 +08:00
info = tr ( " Section GUID: %1 \n Type: %2h \n Full size: %3h (%4) \n Header size: %5h (%6) \n Body size: %7h (%8) \n Data offset: %9h \n Attributes: %10h " )
2014-05-03 19:21:03 +08:00
. arg ( name )
2015-01-31 22:00:00 +08:00
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) )
. hexarg ( guidDefinedSectionHeader - > DataOffset )
. hexarg2 ( guidDefinedSectionHeader - > Attributes , 4 ) ;
2014-05-03 19:21:03 +08:00
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE ;
// Check if section requires processing
if ( guidDefinedSectionHeader - > Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED ) {
// Tiano compressed section
if ( QByteArray ( ( const char * ) & guidDefinedSectionHeader - > SectionDefinitionGuid , sizeof ( EFI_GUID ) ) = = EFI_GUIDED_SECTION_TIANO ) {
algorithm = COMPRESSION_ALGORITHM_UNKNOWN ;
2014-08-14 20:02:35 +08:00
2015-01-31 22:00:00 +08:00
result = decompress ( body , EFI_STANDARD_COMPRESSION , processed , & algorithm ) ;
2014-07-12 18:27:42 +08:00
if ( result )
2014-05-03 19:21:03 +08:00
parseCurrentSection = false ;
2014-11-18 23:01:20 +08:00
if ( algorithm = = COMPRESSION_ALGORITHM_TIANO ) {
info + = tr ( " \n Compression type: Tiano " ) ;
2015-01-31 22:00:00 +08:00
info + = tr ( " \n Decompressed size: %1h (%2) " ) . hexarg ( processed . length ( ) ) . arg ( processed . length ( ) ) ;
2014-11-18 23:01:20 +08:00
}
else if ( algorithm = = COMPRESSION_ALGORITHM_EFI11 ) {
info + = tr ( " \n Compression type: EFI 1.1 " ) ;
2015-01-31 22:00:00 +08:00
info + = tr ( " \n Decompressed size: %1h (%2) " ) . hexarg ( processed . length ( ) ) . arg ( processed . length ( ) ) ;
2014-11-18 23:01:20 +08:00
}
else
info + = tr ( " \n Compression type: unknown " ) ;
2014-05-03 19:21:03 +08:00
}
// LZMA compressed section
else if ( QByteArray ( ( const char * ) & guidDefinedSectionHeader - > SectionDefinitionGuid , sizeof ( EFI_GUID ) ) = = EFI_GUIDED_SECTION_LZMA ) {
algorithm = COMPRESSION_ALGORITHM_UNKNOWN ;
2014-08-14 20:02:35 +08:00
2015-01-31 22:00:00 +08:00
result = decompress ( body , EFI_CUSTOMIZED_COMPRESSION , processed , & algorithm ) ;
2014-11-18 23:01:20 +08:00
if ( result )
2014-05-03 19:21:03 +08:00
parseCurrentSection = false ;
2014-11-18 23:01:20 +08:00
if ( algorithm = = COMPRESSION_ALGORITHM_LZMA ) {
info + = tr ( " \n Compression type: LZMA " ) ;
2015-01-31 22:00:00 +08:00
info + = tr ( " \n Decompressed size: %1h (%2) " ) . hexarg ( processed . length ( ) ) . arg ( processed . length ( ) ) ;
2014-11-18 23:01:20 +08:00
}
else
info + = tr ( " \n Compression type: unknown " ) ;
2014-05-03 19:21:03 +08:00
}
2015-02-13 03:51:23 +08:00
// Signed section
else if ( QByteArray ( ( const char * ) & guidDefinedSectionHeader - > SectionDefinitionGuid , sizeof ( EFI_GUID ) ) = = EFI_FIRMWARE_CONTENTS_SIGNED_GUID ) {
msgSigned = true ;
const WIN_CERTIFICATE * certificateHeader = ( const WIN_CERTIFICATE * ) body . constData ( ) ;
if ( certificateHeader - > CertificateType = = WIN_CERT_TYPE_EFI_GUID ) {
info + = tr ( " \n Signature type: UEFI " ) ;
const WIN_CERTIFICATE_UEFI_GUID * guidCertificateHeader = ( const WIN_CERTIFICATE_UEFI_GUID * ) certificateHeader ;
if ( QByteArray ( ( const char * ) & guidCertificateHeader - > CertType , sizeof ( EFI_GUID ) ) = = EFI_CERT_TYPE_RSA2048_SHA256_GUID ) {
info + = tr ( " \n Signature subtype: RSA2048/SHA256 " ) ;
// TODO: show signature info in Information panel
}
else if ( QByteArray ( ( const char * ) & guidCertificateHeader - > CertType , sizeof ( EFI_GUID ) ) = = EFI_CERT_TYPE_PKCS7_GUID ) {
info + = tr ( " \n Signature subtype: PCKS7 " ) ;
// TODO: show signature info in Information panel
}
else {
info + = tr ( " \n Signature subtype: unknown " ) ;
msgUnknownUefiGuidSignature = true ;
}
}
else if ( certificateHeader - > CertificateType = = WIN_CERT_TYPE_PKCS_SIGNED_DATA ) {
info + = tr ( " \n Signature type: PCKS7 " ) ;
// TODO: show signature info in Information panel
}
else {
info + = tr ( " \n Signature type: unknown " ) ;
msgUnknownSignature = true ;
}
// Add additional to the header
header . append ( body . left ( certificateHeader - > Length ) ) ;
// Get new body
processed = body = body . mid ( certificateHeader - > Length ) ;
2014-11-08 19:40:06 +08:00
}
2014-05-03 19:21:03 +08:00
// Unknown GUIDed section
else {
2014-07-12 18:27:42 +08:00
msgUnknownGuid = true ;
2014-05-03 19:21:03 +08:00
parseCurrentSection = false ;
}
}
// Check if section requires checksum calculation
else if ( guidDefinedSectionHeader - > Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID )
{
// CRC32 section
if ( QByteArray ( ( const char * ) & guidDefinedSectionHeader - > SectionDefinitionGuid , sizeof ( EFI_GUID ) ) = = EFI_GUIDED_SECTION_CRC32 ) {
info + = tr ( " \n Checksum type: CRC32 " ) ;
// Calculate CRC32 of section data
2015-01-31 22:00:00 +08:00
UINT32 crc = crc32 ( 0 , ( const UINT8 * ) body . constData ( ) , body . size ( ) ) ;
2014-07-25 07:59:51 +08:00
// Check stored CRC32
2015-01-31 22:00:00 +08:00
if ( crc = = * ( const UINT32 * ) ( header . constData ( ) + sizeof ( EFI_GUID_DEFINED_SECTION ) ) ) {
2014-05-03 19:21:03 +08:00
info + = tr ( " \n Checksum: valid " ) ;
}
else {
info + = tr ( " \n Checksum: invalid " ) ;
2014-07-12 18:27:42 +08:00
msgInvalidCrc = true ;
2014-05-03 19:21:03 +08:00
}
}
2014-07-25 07:59:51 +08:00
else
2014-07-12 18:27:42 +08:00
msgUnknownAuth = true ;
2014-05-03 19:21:03 +08:00
}
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , algorithm , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
2014-07-12 18:27:42 +08:00
// Show messages
if ( msgUnknownGuid )
msg ( tr ( " parseSection: GUID defined section with unknown processing method " ) , index ) ;
if ( msgUnknownAuth )
msg ( tr ( " parseSection: GUID defined section with unknown authentication method " ) , index ) ;
if ( msgInvalidCrc )
msg ( tr ( " parseSection: GUID defined section with invalid CRC32 " ) , index ) ;
2015-02-13 03:51:23 +08:00
if ( msgSigned )
msg ( tr ( " parseSection: signature may become invalid after any modification " ) , index ) ;
if ( msgUnknownUefiGuidSignature )
msg ( tr ( " parseSection: GUID defined section with unknown signature subtype " ) , index ) ;
if ( msgUnknownSignature )
msg ( tr ( " parseSection: GUID defined section with unknown signature type " ) , index ) ;
2014-07-12 18:27:42 +08:00
if ( ! parseCurrentSection ) {
msg ( tr ( " parseSection: GUID defined section can not be processed " ) , index ) ;
}
2015-01-31 22:00:00 +08:00
else { // Parse processed data
result = parseSections ( processed , index ) ;
2014-05-03 19:21:03 +08:00
if ( result )
return result ;
}
2015-01-31 22:00:00 +08:00
} break ;
2014-05-03 19:21:03 +08:00
case EFI_SECTION_DISPOSABLE :
{
header = section . left ( sizeof ( EFI_DISPOSABLE_SECTION ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( EFI_DISPOSABLE_SECTION ) ) ;
2014-05-03 19:21:03 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
// Parse section body
result = parseSections ( body , index ) ;
if ( result )
return result ;
2015-01-31 22:00:00 +08:00
} break ;
2014-11-02 18:27:54 +08:00
// Leaf sections
case EFI_SECTION_DXE_DEPEX :
case EFI_SECTION_PEI_DEPEX :
case EFI_SECTION_SMM_DEPEX : {
bool msgDepexParseFailed = false ;
headerSize = sizeOfSectionHeader ( sectionHeader ) ;
header = section . left ( headerSize ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( headerSize ) ;
2014-11-02 18:27:54 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) ) ;
2014-11-02 18:27:54 +08:00
// Parse dependency expression
QString str ;
result = parseDepexSection ( body , str ) ;
if ( result )
msgDepexParseFailed = true ;
else if ( str . count ( ) )
info + = tr ( " \n Parsed expression:%1 " ) . arg ( str ) ;
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-11-02 18:27:54 +08:00
// Show messages
if ( msgDepexParseFailed )
msg ( tr ( " parseSection: dependency expression parsing failed " ) , index ) ;
2015-01-31 22:00:00 +08:00
} break ;
case EFI_SECTION_TE : {
headerSize = sizeOfSectionHeader ( sectionHeader ) ;
header = section . left ( headerSize ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( headerSize ) ;
2015-01-31 22:00:00 +08:00
// Get standard info
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) ) ;
// Get TE info
bool msgInvalidSignature = false ;
const EFI_IMAGE_TE_HEADER * teHeader = ( const EFI_IMAGE_TE_HEADER * ) body . constData ( ) ;
UINT32 teFixup = teHeader - > StrippedSize - sizeof ( EFI_IMAGE_TE_HEADER ) ;
if ( teHeader - > Signature ! = EFI_IMAGE_TE_SIGNATURE ) {
info + = tr ( " \n Signature: %1h, invalid " ) . hexarg2 ( teHeader - > Signature , 4 ) ;
msgInvalidSignature = true ;
}
else {
2015-02-06 16:47:19 +08:00
info + = tr ( " \n Signature: %1h \n Machine type: %2 \n Number of sections: %3 \n Subsystem: %4h \n StrippedSize: %5h (%6) \n BaseOfCode: %7h \n RelativeEntryPoint: %8h \n ImageBase: %9h \n EntryPoint: %10h " )
2015-01-31 22:00:00 +08:00
. hexarg2 ( teHeader - > Signature , 4 )
2015-02-06 16:47:19 +08:00
. arg ( machineTypeToQString ( teHeader - > Machine ) )
2015-01-31 22:00:00 +08:00
. arg ( teHeader - > NumberOfSections )
. hexarg2 ( teHeader - > Subsystem , 2 )
. hexarg ( teHeader - > StrippedSize ) . arg ( teHeader - > StrippedSize )
. hexarg ( teHeader - > BaseOfCode )
. hexarg ( teHeader - > AddressOfEntryPoint )
. hexarg ( teHeader - > ImageBase )
. hexarg ( teHeader - > ImageBase + teHeader - > AddressOfEntryPoint - teFixup ) ;
}
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2015-01-31 22:00:00 +08:00
// Show messages
if ( msgInvalidSignature ) {
msg ( " parseSection: TE image with invalid TE signature " , index ) ;
}
// Special case of PEI Core
QModelIndex core = model - > findParentOfType ( index , Types : : File ) ;
2015-02-06 16:47:19 +08:00
if ( core . isValid ( ) & & model - > subtype ( core ) = = EFI_FV_FILETYPE_PEI_CORE
2015-01-31 22:00:00 +08:00
& & oldPeiCoreEntryPoint = = 0 ) {
result = getEntryPoint ( model - > body ( index ) , oldPeiCoreEntryPoint ) ;
if ( result )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseSection: can't get original PEI core entry point " ) , index ) ;
2015-01-31 22:00:00 +08:00
}
} break ;
2014-05-03 19:21:03 +08:00
case EFI_SECTION_PE32 :
2015-01-31 22:00:00 +08:00
case EFI_SECTION_PIC : {
2014-06-19 11:45:20 +08:00
headerSize = sizeOfSectionHeader ( sectionHeader ) ;
2014-05-03 19:21:03 +08:00
header = section . left ( headerSize ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( headerSize ) ;
2014-05-03 19:21:03 +08:00
2015-01-31 22:00:00 +08:00
// Get standard info
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) ) ;
2015-02-06 16:47:19 +08:00
// Get PE info
2015-01-31 22:00:00 +08:00
bool msgInvalidDosSignature = false ;
bool msgInvalidPeSignature = false ;
bool msgUnknownOptionalHeaderSignature = false ;
const EFI_IMAGE_DOS_HEADER * dosHeader = ( const EFI_IMAGE_DOS_HEADER * ) body . constData ( ) ;
if ( dosHeader - > e_magic ! = EFI_IMAGE_DOS_SIGNATURE ) {
info + = tr ( " \n DOS signature: %1h, invalid " ) . hexarg2 ( dosHeader - > e_magic , 4 ) ;
msgInvalidDosSignature = true ;
}
else {
const EFI_IMAGE_PE_HEADER * peHeader = ( EFI_IMAGE_PE_HEADER * ) ( body . constData ( ) + dosHeader - > e_lfanew ) ;
if ( peHeader - > Signature ! = EFI_IMAGE_PE_SIGNATURE ) {
info + = tr ( " \n PE signature: %1h, invalid " ) . hexarg2 ( peHeader - > Signature , 8 ) ;
msgInvalidPeSignature = true ;
}
else {
const EFI_IMAGE_FILE_HEADER * imageFileHeader = ( const EFI_IMAGE_FILE_HEADER * ) ( peHeader + 1 ) ;
2015-02-06 16:47:19 +08:00
info + = tr ( " \n DOS signature: %1h \n PE signature: %2h \n Machine type: %3 \n Number of sections: %4 \n Characteristics: %5h " )
2015-01-31 22:00:00 +08:00
. hexarg2 ( dosHeader - > e_magic , 4 )
. hexarg2 ( peHeader - > Signature , 8 )
2015-02-06 16:47:19 +08:00
. arg ( machineTypeToQString ( imageFileHeader - > Machine ) )
2015-01-31 22:00:00 +08:00
. arg ( imageFileHeader - > NumberOfSections )
. hexarg2 ( imageFileHeader - > Characteristics , 4 ) ;
EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader ;
optionalHeader . H32 = ( const EFI_IMAGE_OPTIONAL_HEADER32 * ) ( imageFileHeader + 1 ) ;
if ( optionalHeader . H32 - > Magic = = EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC ) {
info + = tr ( " \n Optional header signature: %1h \n Subsystem: %2h \n RelativeEntryPoint: %3h \n BaseOfCode: %4h \n ImageBase: %5h \n EntryPoint: %6h " )
. hexarg2 ( optionalHeader . H32 - > Magic , 4 )
. hexarg2 ( optionalHeader . H32 - > Subsystem , 4 )
. hexarg ( optionalHeader . H32 - > AddressOfEntryPoint )
. hexarg ( optionalHeader . H32 - > BaseOfCode )
. hexarg ( optionalHeader . H32 - > ImageBase )
. hexarg ( optionalHeader . H32 - > ImageBase + optionalHeader . H32 - > AddressOfEntryPoint ) ;
}
else if ( optionalHeader . H32 - > Magic = = EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC ) {
info + = tr ( " \n Optional header signature: %1h \n Subsystem: %2h \n RelativeEntryPoint: %3h \n BaseOfCode: %4h \n ImageBase: %5h \n EntryPoint: %6h " )
. hexarg2 ( optionalHeader . H64 - > Magic , 4 )
. hexarg2 ( optionalHeader . H64 - > Subsystem , 4 )
. hexarg ( optionalHeader . H64 - > AddressOfEntryPoint )
. hexarg ( optionalHeader . H64 - > BaseOfCode )
. hexarg ( optionalHeader . H64 - > ImageBase )
. hexarg ( optionalHeader . H64 - > ImageBase + optionalHeader . H64 - > AddressOfEntryPoint ) ;
}
else {
info + = tr ( " \n Optional header signature: %1h, unknown " ) . hexarg2 ( optionalHeader . H64 - > Magic , 4 ) ;
msgUnknownOptionalHeaderSignature = true ;
}
}
}
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
2015-01-31 22:00:00 +08:00
// Show messages
if ( msgInvalidDosSignature ) {
msg ( " parseSection: PE32 image with invalid DOS signature " , index ) ;
}
2015-02-06 16:47:19 +08:00
if ( msgInvalidPeSignature ) {
2015-01-31 22:00:00 +08:00
msg ( " parseSection: PE32 image with invalid PE signature " , index ) ;
}
if ( msgUnknownOptionalHeaderSignature ) {
msg ( " parseSection: PE32 image with unknown optional header signature " , index ) ;
}
2014-05-03 19:21:03 +08:00
// Special case of PEI Core
2015-01-31 22:00:00 +08:00
QModelIndex core = model - > findParentOfType ( index , Types : : File ) ;
2015-02-06 16:47:19 +08:00
if ( core . isValid ( ) & & model - > subtype ( core ) = = EFI_FV_FILETYPE_PEI_CORE
2014-11-18 23:01:20 +08:00
& & oldPeiCoreEntryPoint = = 0 ) {
2014-05-03 19:21:03 +08:00
result = getEntryPoint ( model - > body ( index ) , oldPeiCoreEntryPoint ) ;
if ( result )
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseSection: can't get original PEI core entry point " ) , index ) ;
2014-05-03 19:21:03 +08:00
}
2015-01-31 22:00:00 +08:00
} break ;
case EFI_SECTION_COMPATIBILITY16 : {
headerSize = sizeOfSectionHeader ( sectionHeader ) ;
header = section . left ( headerSize ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( headerSize ) ;
2015-01-31 22:00:00 +08:00
// Get info
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) ) ;
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2015-01-31 22:00:00 +08:00
} break ;
2014-05-03 19:21:03 +08:00
case EFI_SECTION_FREEFORM_SUBTYPE_GUID : {
header = section . left ( sizeof ( EFI_FREEFORM_SUBTYPE_GUID_SECTION ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( EFI_FREEFORM_SUBTYPE_GUID_SECTION ) ) ;
2014-05-03 19:21:03 +08:00
2015-01-31 22:00:00 +08:00
const EFI_FREEFORM_SUBTYPE_GUID_SECTION * fsgHeader = ( const EFI_FREEFORM_SUBTYPE_GUID_SECTION * ) sectionHeader ;
2014-05-03 19:21:03 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) \n Subtype GUID: %8 " )
. hexarg2 ( fsgHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) )
2014-05-03 19:21:03 +08:00
. arg ( guidToQString ( fsgHeader - > SubTypeGuid ) ) ;
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2015-01-31 22:00:00 +08:00
// Rename section
model - > setName ( index , guidToQString ( fsgHeader - > SubTypeGuid ) ) ;
} break ;
2014-05-03 19:21:03 +08:00
case EFI_SECTION_VERSION : {
header = section . left ( sizeof ( EFI_VERSION_SECTION ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( EFI_VERSION_SECTION ) ) ;
2014-05-03 19:21:03 +08:00
2015-01-31 22:00:00 +08:00
const EFI_VERSION_SECTION * versionHeader = ( const EFI_VERSION_SECTION * ) sectionHeader ;
2014-05-03 19:21:03 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) \n Build number: %8 \n Version string: %9 " )
. hexarg2 ( versionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) )
2014-10-30 11:56:37 +08:00
. arg ( versionHeader - > BuildNumber )
2014-05-03 19:21:03 +08:00
. arg ( QString : : fromUtf16 ( ( const ushort * ) body . constData ( ) ) ) ;
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2015-01-31 22:00:00 +08:00
} break ;
2014-05-03 19:21:03 +08:00
case EFI_SECTION_USER_INTERFACE : {
header = section . left ( sizeof ( EFI_USER_INTERFACE_SECTION ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( EFI_USER_INTERFACE_SECTION ) ) ;
2014-05-03 19:21:03 +08:00
QString text = QString : : fromUtf16 ( ( const ushort * ) body . constData ( ) ) ;
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) \n Text: %8 " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) )
2014-05-03 19:21:03 +08:00
. arg ( text ) ;
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
// Rename parent file
2015-01-31 22:00:00 +08:00
model - > setText ( model - > findParentOfType ( parent , Types : : File ) , text ) ;
} break ;
2014-05-03 19:21:03 +08:00
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE : {
header = section . left ( sizeof ( EFI_FIRMWARE_VOLUME_IMAGE_SECTION ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( EFI_FIRMWARE_VOLUME_IMAGE_SECTION ) ) ;
2014-05-03 19:21:03 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
// Parse section body as BIOS space
result = parseBios ( body , index ) ;
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseSection: parsing firmware volume image section as BIOS failed with error \" %1 \" " ) . arg ( errorMessage ( result ) ) , index ) ;
2014-05-03 19:21:03 +08:00
return result ;
}
2015-01-31 22:00:00 +08:00
} break ;
2014-05-03 19:21:03 +08:00
case EFI_SECTION_RAW : {
2014-11-02 18:27:54 +08:00
bool parsed = false ;
2014-05-03 19:21:03 +08:00
header = section . left ( sizeof ( EFI_RAW_SECTION ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( EFI_RAW_SECTION ) ) ;
2014-05-03 19:21:03 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) ) ;
2014-05-03 19:21:03 +08:00
2014-11-02 18:27:54 +08:00
// Check for apriori file
QModelIndex parentFile = model - > findParentOfType ( parent , Types : : File ) ;
QByteArray parentFileGuid = model - > header ( parentFile ) . left ( sizeof ( EFI_GUID ) ) ;
if ( parentFileGuid = = EFI_PEI_APRIORI_FILE_GUID ) {
// Mark file as parsed
parsed = true ;
// Parse apriori file list
QString str ;
parseAprioriRawSection ( body , str ) ;
if ( str . count ( ) )
info + = tr ( " \n File list:%1 " ) . arg ( str ) ;
2015-01-31 22:00:00 +08:00
// Set parent file text
model - > setText ( parentFile , tr ( " PEI apriori file " ) ) ;
2014-11-02 18:27:54 +08:00
}
else if ( parentFileGuid = = EFI_DXE_APRIORI_FILE_GUID ) {
// Mark file as parsed
parsed = true ;
// Parse apriori file list
QString str ;
parseAprioriRawSection ( body , str ) ;
if ( str . count ( ) )
info + = tr ( " \n File list:%1 " ) . arg ( str ) ;
2015-01-31 22:00:00 +08:00
// Set parent file text
model - > setText ( parentFile , tr ( " DXE apriori file " ) ) ;
2014-11-02 18:27:54 +08:00
}
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2014-05-03 19:21:03 +08:00
// Parse section body as BIOS space
2014-11-02 18:27:54 +08:00
if ( ! parsed ) {
result = parseBios ( body , index ) ;
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " parseSection: parsing raw section as BIOS failed with error \" %1 \" " ) . arg ( errorMessage ( result ) ) , index ) ;
2014-11-02 18:27:54 +08:00
return result ;
}
2014-05-03 19:21:03 +08:00
}
2015-01-31 22:00:00 +08:00
} break ;
2015-01-26 06:55:05 +08:00
2015-01-31 22:00:00 +08:00
case SCT_SECTION_POSTCODE :
2015-02-13 03:51:23 +08:00
case INSYDE_SECTION_POSTCODE : {
2015-01-26 06:55:05 +08:00
header = section . left ( sizeof ( POSTCODE_SECTION ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( POSTCODE_SECTION ) ) ;
2015-01-26 06:55:05 +08:00
2015-01-31 22:00:00 +08:00
const POSTCODE_SECTION * postcodeHeader = ( const POSTCODE_SECTION * ) sectionHeader ;
2015-01-26 06:55:05 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) \n Postcode: %8h " )
. hexarg2 ( postcodeHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) )
. hexarg ( postcodeHeader - > Postcode ) ;
2015-01-26 06:55:05 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
2015-01-31 22:00:00 +08:00
} break ;
2014-12-11 02:18:05 +08:00
2014-05-03 19:21:03 +08:00
default :
header = section . left ( sizeof ( EFI_COMMON_SECTION_HEADER ) ) ;
2015-02-18 22:35:44 +08:00
body = section . mid ( sizeof ( EFI_COMMON_SECTION_HEADER ) ) ;
2014-05-03 19:21:03 +08:00
// Get info
2015-01-31 22:00:00 +08:00
info = tr ( " Type: %1h \n Full size: %2h (%3) \n Header size: %4h (%5) \n Body size: %6h (%7) " )
. hexarg2 ( sectionHeader - > Type , 2 )
. hexarg ( section . size ( ) ) . arg ( section . size ( ) )
. hexarg ( header . size ( ) ) . arg ( header . size ( ) )
. hexarg ( body . size ( ) ) . arg ( body . size ( ) ) ;
2014-05-03 19:21:03 +08:00
// Add tree item
2015-02-06 16:47:19 +08:00
index = model - > addItem ( Types : : Section , sectionHeader - > Type , COMPRESSION_ALGORITHM_NONE , name , " " , info , header , body , QByteArray ( ) , parent , mode ) ;
msg ( tr ( " parseSection: section with unknown type %1h " ) . hexarg2 ( sectionHeader - > Type , 2 ) , index ) ;
2014-05-03 19:21:03 +08:00
}
return ERR_SUCCESS ;
}
// Operations on tree items
UINT8 FfsEngine : : create ( const QModelIndex & index , const UINT8 type , const QByteArray & header , const QByteArray & body , const UINT8 mode , const UINT8 action , const UINT8 algorithm )
{
QByteArray created ;
UINT8 result ;
QModelIndex fileIndex ;
if ( ! index . isValid ( ) | | ! index . parent ( ) . isValid ( ) )
return ERR_INVALID_PARAMETER ;
QModelIndex parent ;
if ( mode = = CREATE_MODE_BEFORE | | mode = = CREATE_MODE_AFTER )
parent = index . parent ( ) ;
else
parent = index ;
// Create item
if ( type = = Types : : Region ) {
2015-02-06 16:47:19 +08:00
UINT8 type = model - > subtype ( index ) ;
switch ( type ) {
case Subtypes : : BiosRegion :
2014-05-03 19:21:03 +08:00
result = parseBiosRegion ( body , fileIndex , index , mode ) ;
break ;
2015-02-06 16:47:19 +08:00
case Subtypes : : MeRegion :
2014-05-03 19:21:03 +08:00
result = parseMeRegion ( body , fileIndex , index , mode ) ;
break ;
2015-02-06 16:47:19 +08:00
case Subtypes : : GbeRegion :
2014-05-03 19:21:03 +08:00
result = parseGbeRegion ( body , fileIndex , index , mode ) ;
break ;
2015-02-06 16:47:19 +08:00
case Subtypes : : PdrRegion :
2014-05-03 19:21:03 +08:00
result = parsePdrRegion ( body , fileIndex , index , mode ) ;
break ;
default :
return ERR_NOT_IMPLEMENTED ;
}
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME )
2014-05-03 19:21:03 +08:00
return result ;
// Set action
model - > setAction ( fileIndex , action ) ;
}
2015-01-31 22:00:00 +08:00
else if ( type = = Types : : Volume ) {
QByteArray volume ;
if ( header . isEmpty ( ) ) // Whole volume
volume . append ( body ) ;
else { // Body only
volume . append ( model - > header ( index ) ) . 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 ( ) ;
bool erasePolarity = volumeHeader - > Attributes & EFI_FVB_ERASE_POLARITY ;
volume . append ( QByteArray ( sizeDiff , erasePolarity ? ' \xFF ' : ' \x00 ' ) ) ;
}
}
result = parseVolume ( volume , fileIndex , index , mode ) ;
if ( result )
return result ;
// Set action
model - > setAction ( fileIndex , action ) ;
}
2014-05-03 19:21:03 +08:00
else if ( type = = Types : : File ) {
if ( model - > type ( parent ) ! = Types : : Volume )
return ERR_INVALID_FILE ;
2015-01-31 22:00:00 +08:00
const EFI_FIRMWARE_VOLUME_HEADER * volumeHeader = ( const EFI_FIRMWARE_VOLUME_HEADER * ) model - > header ( parent ) . constData ( ) ;
2014-05-03 19:21:03 +08:00
UINT8 revision = volumeHeader - > Revision ;
bool erasePolarity = volumeHeader - > Attributes & EFI_FVB_ERASE_POLARITY ;
if ( header . size ( ) ! = sizeof ( EFI_FFS_FILE_HEADER ) )
return ERR_INVALID_FILE ;
QByteArray newHeader = header ;
EFI_FFS_FILE_HEADER * fileHeader = ( EFI_FFS_FILE_HEADER * ) newHeader . data ( ) ;
2015-01-31 22:00:00 +08:00
2014-05-03 19:21:03 +08:00
// Correct file size
UINT8 tailSize = fileHeader - > Attributes & FFS_ATTRIB_TAIL_PRESENT ? sizeof ( UINT16 ) : 0 ;
2014-07-25 07:59:51 +08:00
uint32ToUint24 ( sizeof ( EFI_FFS_FILE_HEADER ) + body . size ( ) + tailSize , fileHeader - > Size ) ;
2014-05-03 19:21:03 +08:00
// Recalculate header checksum
fileHeader - > IntegrityCheck . Checksum . Header = 0 ;
fileHeader - > IntegrityCheck . Checksum . File = 0 ;
2015-01-31 22:00:00 +08:00
fileHeader - > IntegrityCheck . Checksum . Header = calculateChecksum8 ( ( const UINT8 * ) fileHeader , sizeof ( EFI_FFS_FILE_HEADER ) - 1 ) ;
2014-05-03 19:21:03 +08:00
// Recalculate data checksum, if needed
if ( fileHeader - > Attributes & FFS_ATTRIB_CHECKSUM )
2015-01-31 22:00:00 +08:00
fileHeader - > IntegrityCheck . Checksum . File = calculateChecksum8 ( ( const UINT8 * ) body . constData ( ) , body . size ( ) ) ;
2014-05-03 19:21:03 +08:00
else if ( revision = = 1 )
fileHeader - > IntegrityCheck . Checksum . File = FFS_FIXED_CHECKSUM ;
else
fileHeader - > IntegrityCheck . Checksum . File = FFS_FIXED_CHECKSUM2 ;
// Append body
created . append ( body ) ;
// Append tail, if needed
if ( tailSize ) {
UINT8 ht = ~ fileHeader - > IntegrityCheck . Checksum . Header ;
UINT8 ft = ~ fileHeader - > IntegrityCheck . Checksum . File ;
created . append ( ht ) . append ( ft ) ;
}
// Set file state
UINT8 state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | EFI_FILE_HEADER_CONSTRUCTION ;
if ( erasePolarity )
state = ~ state ;
fileHeader - > State = state ;
// Prepend header
created . prepend ( newHeader ) ;
// Parse file
result = parseFile ( created , fileIndex , erasePolarity ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE , index , mode ) ;
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME )
2014-05-03 19:21:03 +08:00
return result ;
// Set action
model - > setAction ( fileIndex , action ) ;
// Rebase all PEI-files that follow
rebasePeiFiles ( fileIndex ) ;
}
else if ( type = = Types : : Section ) {
if ( model - > type ( parent ) ! = Types : : File & & model - > type ( parent ) ! = Types : : Section )
return ERR_INVALID_SECTION ;
if ( header . size ( ) < ( int ) sizeof ( EFI_COMMON_SECTION_HEADER ) )
return ERR_INVALID_SECTION ;
QByteArray newHeader = header ;
EFI_COMMON_SECTION_HEADER * commonHeader = ( EFI_COMMON_SECTION_HEADER * ) newHeader . data ( ) ;
switch ( commonHeader - > Type )
{
case EFI_SECTION_COMPRESSION : {
EFI_COMPRESSION_SECTION * sectionHeader = ( EFI_COMPRESSION_SECTION * ) newHeader . data ( ) ;
// Correct uncompressed size
sectionHeader - > UncompressedLength = body . size ( ) ;
// Set compression type
if ( algorithm = = COMPRESSION_ALGORITHM_NONE )
sectionHeader - > CompressionType = EFI_NOT_COMPRESSED ;
else if ( algorithm = = COMPRESSION_ALGORITHM_EFI11 | | algorithm = = COMPRESSION_ALGORITHM_TIANO )
sectionHeader - > CompressionType = EFI_STANDARD_COMPRESSION ;
else if ( algorithm = = COMPRESSION_ALGORITHM_LZMA | | algorithm = = COMPRESSION_ALGORITHM_IMLZMA )
sectionHeader - > CompressionType = EFI_CUSTOMIZED_COMPRESSION ;
else
return ERR_UNKNOWN_COMPRESSION_ALGORITHM ;
// Compress body
QByteArray compressed ;
result = compress ( body , algorithm , compressed ) ;
if ( result )
return result ;
// Correct section size
uint32ToUint24 ( header . size ( ) + compressed . size ( ) , commonHeader - > Size ) ;
// Append header and body
created . append ( newHeader ) . append ( compressed ) ;
// Parse section
QModelIndex sectionIndex ;
result = parseSection ( created , sectionIndex , index , mode ) ;
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME )
2014-05-03 19:21:03 +08:00
return result ;
// Set create action
model - > setAction ( sectionIndex , action ) ;
// Find parent file for rebase
fileIndex = model - > findParentOfType ( parent , Types : : File ) ;
}
break ;
case EFI_SECTION_GUID_DEFINED : {
// Compress body
QByteArray compressed ;
result = compress ( body , algorithm , compressed ) ;
if ( result )
return result ;
// Correct section size
uint32ToUint24 ( header . size ( ) + compressed . size ( ) , commonHeader - > Size ) ;
// Append header and body
created . append ( newHeader ) . append ( compressed ) ;
// Parse section
QModelIndex sectionIndex ;
result = parseSection ( created , sectionIndex , index , mode ) ;
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME )
2014-05-03 19:21:03 +08:00
return result ;
// Set create action
model - > setAction ( sectionIndex , action ) ;
// Find parent file for rebase
fileIndex = model - > findParentOfType ( parent , Types : : File ) ;
}
break ;
default :
// Correct section size
uint32ToUint24 ( header . size ( ) + body . size ( ) , commonHeader - > Size ) ;
// Append header and body
created . append ( newHeader ) . append ( body ) ;
// Parse section
QModelIndex sectionIndex ;
result = parseSection ( created , sectionIndex , index , mode ) ;
2014-11-02 18:27:54 +08:00
if ( result & & result ! = ERR_VOLUMES_NOT_FOUND & & result ! = ERR_INVALID_VOLUME )
2014-05-03 19:21:03 +08:00
return result ;
// Set create action
model - > setAction ( sectionIndex , action ) ;
// Find parent file for rebase
fileIndex = model - > findParentOfType ( parent , Types : : File ) ;
}
// Rebase all PEI-files that follow
rebasePeiFiles ( fileIndex ) ;
}
else
return ERR_NOT_IMPLEMENTED ;
return ERR_SUCCESS ;
}
void FfsEngine : : rebasePeiFiles ( const QModelIndex & index )
{
// Rebase all PE32 and TE sections in PEI-files after modified file
for ( int i = index . row ( ) ; i < model - > rowCount ( index . parent ( ) ) ; i + + ) {
// PEI-file
QModelIndex currentFileIndex = index . parent ( ) . child ( i , 0 ) ;
2015-02-06 16:47:19 +08:00
if ( model - > subtype ( currentFileIndex ) = = EFI_FV_FILETYPE_PEI_CORE | |
model - > subtype ( currentFileIndex ) = = EFI_FV_FILETYPE_PEIM | |
model - > subtype ( currentFileIndex ) = = EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ) {
2014-05-03 19:21:03 +08:00
for ( int j = 0 ; j < model - > rowCount ( currentFileIndex ) ; j + + ) {
// Section in that file
QModelIndex currentSectionIndex = currentFileIndex . child ( j , 0 ) ;
// If section stores PE32 or TE image
2015-02-06 16:47:19 +08:00
if ( model - > subtype ( currentSectionIndex ) = = EFI_SECTION_PE32 | | model - > subtype ( currentSectionIndex ) = = EFI_SECTION_TE )
2014-05-03 19:21:03 +08:00
// Set rebase action
model - > setAction ( currentSectionIndex , Actions : : Rebase ) ;
}
}
}
}
UINT8 FfsEngine : : insert ( const QModelIndex & index , const QByteArray & object , const UINT8 mode )
{
if ( ! index . isValid ( ) | | ! index . parent ( ) . isValid ( ) )
return ERR_INVALID_PARAMETER ;
QModelIndex parent ;
if ( mode = = CREATE_MODE_BEFORE | | mode = = CREATE_MODE_AFTER )
parent = index . parent ( ) ;
else
parent = index ;
// Determine type of item to insert
UINT8 type ;
UINT32 headerSize ;
if ( model - > type ( parent ) = = Types : : Volume ) {
type = Types : : File ;
headerSize = sizeof ( EFI_FFS_FILE_HEADER ) ;
}
else if ( model - > type ( parent ) = = Types : : File ) {
type = Types : : Section ;
2015-01-31 22:00:00 +08:00
const EFI_COMMON_SECTION_HEADER * commonHeader = ( EFI_COMMON_SECTION_HEADER * ) object . constData ( ) ;
2014-06-19 11:45:20 +08:00
headerSize = sizeOfSectionHeader ( commonHeader ) ;
2014-05-03 19:21:03 +08:00
}
else if ( model - > type ( parent ) = = Types : : Section ) {
type = Types : : Section ;
2015-01-31 22:00:00 +08:00
const EFI_COMMON_SECTION_HEADER * commonHeader = ( EFI_COMMON_SECTION_HEADER * ) object . constData ( ) ;
2014-06-19 11:45:20 +08:00
headerSize = sizeOfSectionHeader ( commonHeader ) ;
2014-05-03 19:21:03 +08:00
}
else
return ERR_NOT_IMPLEMENTED ;
return create ( index , type , object . left ( headerSize ) , object . right ( object . size ( ) - headerSize ) , mode , Actions : : Insert ) ;
}
UINT8 FfsEngine : : replace ( const QModelIndex & index , const QByteArray & object , const UINT8 mode )
{
if ( ! index . isValid ( ) )
return ERR_INVALID_PARAMETER ;
// Determine type of item to replace
UINT32 headerSize ;
UINT8 result ;
if ( model - > type ( index ) = = Types : : Region ) {
if ( mode = = REPLACE_MODE_AS_IS )
result = create ( index , Types : : Region , QByteArray ( ) , object , CREATE_MODE_AFTER , Actions : : Replace ) ;
else
return ERR_NOT_IMPLEMENTED ;
}
2015-01-31 22:00:00 +08:00
else if ( model - > type ( index ) = = Types : : Volume ) {
if ( mode = = REPLACE_MODE_AS_IS ) {
result = create ( index , Types : : Volume , QByteArray ( ) , object , CREATE_MODE_AFTER , Actions : : Replace ) ;
}
else if ( mode = = REPLACE_MODE_BODY ) {
result = create ( index , Types : : Volume , model - > header ( index ) , object , CREATE_MODE_AFTER , Actions : : Replace ) ;
}
else
return ERR_NOT_IMPLEMENTED ;
}
2014-05-03 19:21:03 +08:00
else if ( model - > type ( index ) = = Types : : File ) {
if ( mode = = REPLACE_MODE_AS_IS ) {
headerSize = sizeof ( EFI_FFS_FILE_HEADER ) ;
result = create ( index , Types : : File , object . left ( headerSize ) , object . right ( object . size ( ) - headerSize ) , CREATE_MODE_AFTER , Actions : : Replace ) ;
}
else if ( mode = = REPLACE_MODE_BODY )
result = create ( index , Types : : File , model - > header ( index ) , object , CREATE_MODE_AFTER , Actions : : Replace ) ;
else
return ERR_NOT_IMPLEMENTED ;
}
else if ( model - > type ( index ) = = Types : : Section ) {
if ( mode = = REPLACE_MODE_AS_IS ) {
2015-01-31 22:00:00 +08:00
const EFI_COMMON_SECTION_HEADER * commonHeader = ( const EFI_COMMON_SECTION_HEADER * ) object . constData ( ) ;
2014-06-19 11:45:20 +08:00
headerSize = sizeOfSectionHeader ( commonHeader ) ;
2014-05-03 19:21:03 +08:00
result = create ( index , Types : : Section , object . left ( headerSize ) , object . right ( object . size ( ) - headerSize ) , CREATE_MODE_AFTER , Actions : : Replace ) ;
}
else if ( mode = = REPLACE_MODE_BODY ) {
result = create ( index , Types : : Section , model - > header ( index ) , object , CREATE_MODE_AFTER , Actions : : Replace , model - > compression ( index ) ) ;
}
else
return ERR_NOT_IMPLEMENTED ;
}
else
return ERR_NOT_IMPLEMENTED ;
// Check create result
if ( result )
return result ;
// Set remove action to replaced item
model - > setAction ( index , Actions : : Remove ) ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : extract ( const QModelIndex & index , QByteArray & extracted , const UINT8 mode )
{
if ( ! index . isValid ( ) )
return ERR_INVALID_PARAMETER ;
if ( mode = = EXTRACT_MODE_AS_IS ) {
2015-01-31 22:00:00 +08:00
// Extract as is, with header and body
2014-05-03 19:21:03 +08:00
extracted . clear ( ) ;
extracted . append ( model - > header ( index ) ) ;
extracted . append ( model - > body ( index ) ) ;
2015-01-31 22:00:00 +08:00
if ( model - > type ( index ) = = Types : : File ) {
//!TODO: add volume revision check, maybe?
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) model - > header ( index ) . constData ( ) ;
if ( fileHeader - > Attributes & FFS_ATTRIB_TAIL_PRESENT ) {
UINT8 ht = ~ fileHeader - > IntegrityCheck . Checksum . Header ;
UINT8 ft = ~ fileHeader - > IntegrityCheck . Checksum . File ;
extracted . append ( ht ) . append ( ft ) ;
}
}
2014-05-03 19:21:03 +08:00
}
else if ( mode = = EXTRACT_MODE_BODY ) {
// Extract without header and tail
extracted . clear ( ) ;
// Special case of compressed bodies
if ( model - > type ( index ) = = Types : : Section ) {
QByteArray decompressed ;
UINT8 result ;
2015-02-06 16:47:19 +08:00
if ( model - > subtype ( index ) = = EFI_SECTION_COMPRESSION ) {
2015-01-31 22:00:00 +08:00
const EFI_COMPRESSION_SECTION * compressedHeader = ( const EFI_COMPRESSION_SECTION * ) model - > header ( index ) . constData ( ) ;
2014-05-03 19:21:03 +08:00
result = decompress ( model - > body ( index ) , compressedHeader - > CompressionType , decompressed ) ;
if ( result )
return result ;
extracted . append ( decompressed ) ;
return ERR_SUCCESS ;
}
2015-02-06 16:47:19 +08:00
else if ( model - > subtype ( index ) = = EFI_SECTION_GUID_DEFINED ) {
2014-05-03 19:21:03 +08:00
QByteArray decompressed ;
// Check if section requires processing
2015-01-31 22:00:00 +08:00
const EFI_GUID_DEFINED_SECTION * guidDefinedSectionHeader = ( const EFI_GUID_DEFINED_SECTION * ) model - > header ( index ) . constData ( ) ;
2014-05-03 19:21:03 +08:00
if ( guidDefinedSectionHeader - > Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED ) {
// Try to decompress section body using both known compression algorithms
result = decompress ( model - > body ( index ) , EFI_STANDARD_COMPRESSION , decompressed ) ;
if ( result ) {
result = decompress ( model - > body ( index ) , EFI_CUSTOMIZED_COMPRESSION , decompressed ) ;
if ( result )
return result ;
}
extracted . append ( decompressed ) ;
return ERR_SUCCESS ;
}
}
}
extracted . append ( model - > body ( index ) ) ;
}
else
return ERR_UNKNOWN_EXTRACT_MODE ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : remove ( const QModelIndex & index )
{
if ( ! index . isValid ( ) )
return ERR_INVALID_PARAMETER ;
// Set action for the item
model - > setAction ( index , Actions : : Remove ) ;
QModelIndex fileIndex ;
if ( model - > type ( index ) = = Types : : Volume & & model - > rowCount ( index ) > 0 )
fileIndex = index . child ( 0 , 0 ) ;
else if ( model - > type ( index ) = = Types : : File )
fileIndex = index ;
else if ( model - > type ( index ) = = Types : : Section )
fileIndex = model - > findParentOfType ( index , Types : : File ) ;
else
return ERR_SUCCESS ;
// Rebase all PEI-files that follow
rebasePeiFiles ( fileIndex ) ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : rebuild ( const QModelIndex & index )
{
if ( ! index . isValid ( ) )
return ERR_INVALID_PARAMETER ;
// Set action for the item
model - > setAction ( index , Actions : : Rebuild ) ;
QModelIndex fileIndex ;
if ( model - > type ( index ) = = Types : : Volume & & model - > rowCount ( index ) > 0 )
fileIndex = index . child ( 0 , 0 ) ;
else if ( model - > type ( index ) = = Types : : File )
fileIndex = index ;
else if ( model - > type ( index ) = = Types : : Section )
fileIndex = model - > findParentOfType ( index , Types : : File ) ;
else
return ERR_SUCCESS ;
// Rebase all PEI-files that follow
rebasePeiFiles ( fileIndex ) ;
return ERR_SUCCESS ;
}
// Compression routines
UINT8 FfsEngine : : decompress ( const QByteArray & compressedData , const UINT8 compressionType , QByteArray & decompressedData , UINT8 * algorithm )
{
2015-01-31 22:00:00 +08:00
const UINT8 * data ;
2014-05-03 19:21:03 +08:00
UINT32 dataSize ;
UINT8 * decompressed ;
UINT32 decompressedSize = 0 ;
UINT8 * scratch ;
UINT32 scratchSize = 0 ;
2015-01-31 22:00:00 +08:00
const EFI_TIANO_HEADER * header ;
2014-05-03 19:21:03 +08:00
switch ( compressionType )
{
case EFI_NOT_COMPRESSED :
decompressedData = compressedData ;
if ( algorithm )
* algorithm = COMPRESSION_ALGORITHM_NONE ;
return ERR_SUCCESS ;
case EFI_STANDARD_COMPRESSION :
// Get buffer sizes
2015-01-31 22:00:00 +08:00
data = ( UINT8 * ) compressedData . data ( ) ;
2014-05-03 19:21:03 +08:00
dataSize = compressedData . size ( ) ;
// Check header to be valid
2015-01-31 22:00:00 +08:00
header = ( const EFI_TIANO_HEADER * ) data ;
2014-05-03 19:21:03 +08:00
if ( header - > CompSize + sizeof ( EFI_TIANO_HEADER ) ! = dataSize )
return ERR_STANDARD_DECOMPRESSION_FAILED ;
// Get info function is the same for both algorithms
if ( ERR_SUCCESS ! = EfiTianoGetInfo ( data , dataSize , & decompressedSize , & scratchSize ) )
return ERR_STANDARD_DECOMPRESSION_FAILED ;
// Allocate memory
decompressed = new UINT8 [ decompressedSize ] ;
scratch = new UINT8 [ scratchSize ] ;
// Decompress section data
2014-11-22 01:37:53 +08:00
2014-05-03 19:21:03 +08:00
//TODO: separate EFI1.1 from Tiano another way
// Try Tiano decompression first
if ( ERR_SUCCESS ! = TianoDecompress ( data , dataSize , decompressed , decompressedSize , scratch , scratchSize ) ) {
// Not Tiano, try EFI 1.1
if ( ERR_SUCCESS ! = EfiDecompress ( data , dataSize , decompressed , decompressedSize , scratch , scratchSize ) ) {
if ( algorithm )
* algorithm = COMPRESSION_ALGORITHM_UNKNOWN ;
2014-11-22 01:37:53 +08:00
2014-05-03 19:21:03 +08:00
delete [ ] decompressed ;
delete [ ] scratch ;
return ERR_STANDARD_DECOMPRESSION_FAILED ;
}
else if ( algorithm )
* algorithm = COMPRESSION_ALGORITHM_EFI11 ;
}
else if ( algorithm )
* algorithm = COMPRESSION_ALGORITHM_TIANO ;
decompressedData = QByteArray ( ( const char * ) decompressed , decompressedSize ) ;
delete [ ] decompressed ;
delete [ ] scratch ;
return ERR_SUCCESS ;
case EFI_CUSTOMIZED_COMPRESSION :
// Get buffer sizes
2015-01-31 22:00:00 +08:00
data = ( const UINT8 * ) compressedData . constData ( ) ;
2014-05-03 19:21:03 +08:00
dataSize = compressedData . size ( ) ;
// Get info
if ( ERR_SUCCESS ! = LzmaGetInfo ( data , dataSize , & decompressedSize ) )
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED ;
// Allocate memory
decompressed = new UINT8 [ decompressedSize ] ;
// Decompress section data
if ( ERR_SUCCESS ! = LzmaDecompress ( data , dataSize , decompressed ) ) {
// Intel modified LZMA workaround
EFI_COMMON_SECTION_HEADER * shittySectionHeader ;
UINT32 shittySectionSize ;
// Shitty compressed section with a section header between COMPRESSED_SECTION_HEADER and LZMA_HEADER
// We must determine section header size by checking it's type before we can unpack that non-standard compressed section
shittySectionHeader = ( EFI_COMMON_SECTION_HEADER * ) data ;
2014-06-19 11:45:20 +08:00
shittySectionSize = sizeOfSectionHeader ( shittySectionHeader ) ;
2014-05-03 19:21:03 +08:00
// Decompress section data once again
data + = shittySectionSize ;
// Get info again
if ( ERR_SUCCESS ! = LzmaGetInfo ( data , dataSize , & decompressedSize ) ) {
delete [ ] decompressed ;
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED ;
}
// Decompress section data again
if ( ERR_SUCCESS ! = LzmaDecompress ( data , dataSize , decompressed ) ) {
if ( algorithm )
* algorithm = COMPRESSION_ALGORITHM_UNKNOWN ;
delete [ ] decompressed ;
return ERR_CUSTOMIZED_DECOMPRESSION_FAILED ;
}
else {
if ( algorithm )
* algorithm = COMPRESSION_ALGORITHM_IMLZMA ;
decompressedData = QByteArray ( ( const char * ) decompressed , decompressedSize ) ;
}
}
else {
if ( algorithm )
* algorithm = COMPRESSION_ALGORITHM_LZMA ;
decompressedData = QByteArray ( ( const char * ) decompressed , decompressedSize ) ;
}
delete [ ] decompressed ;
return ERR_SUCCESS ;
default :
2015-02-06 16:47:19 +08:00
msg ( tr ( " decompress: unknown compression type %1 " ) . arg ( compressionType ) ) ;
2014-05-03 19:21:03 +08:00
if ( algorithm )
* algorithm = COMPRESSION_ALGORITHM_UNKNOWN ;
return ERR_UNKNOWN_COMPRESSION_ALGORITHM ;
}
}
UINT8 FfsEngine : : compress ( const QByteArray & data , const UINT8 algorithm , QByteArray & compressedData )
{
UINT8 * compressed ;
2014-07-25 07:59:51 +08:00
2014-05-03 19:21:03 +08:00
switch ( algorithm ) {
case COMPRESSION_ALGORITHM_NONE :
{
compressedData = data ;
return ERR_SUCCESS ;
}
break ;
case COMPRESSION_ALGORITHM_EFI11 :
{
2014-11-11 00:48:59 +08:00
// Try legacy function first
UINT32 compressedSize = 0 ;
if ( EfiCompressLegacy ( data . constData ( ) , data . size ( ) , NULL , & compressedSize ) ! = ERR_BUFFER_TOO_SMALL )
return ERR_STANDARD_COMPRESSION_FAILED ;
compressed = new UINT8 [ compressedSize ] ;
if ( EfiCompressLegacy ( data . constData ( ) , data . size ( ) , compressed , & compressedSize ) ! = ERR_SUCCESS ) {
delete [ ] compressed ;
return ERR_STANDARD_COMPRESSION_FAILED ;
}
compressedData = QByteArray ( ( const char * ) compressed , compressedSize ) ;
// Check that compressed data can be decompressed normally
QByteArray decompressed ;
if ( decompress ( compressedData , EFI_STANDARD_COMPRESSION , decompressed , NULL ) = = ERR_SUCCESS
& & decompressed = = data ) {
delete [ ] compressed ;
return ERR_SUCCESS ;
}
delete [ ] compressed ;
// Legacy function failed, use current one
compressedSize = 0 ;
2014-07-05 20:56:56 +08:00
if ( EfiCompress ( data . constData ( ) , data . size ( ) , NULL , & compressedSize ) ! = ERR_BUFFER_TOO_SMALL )
2014-05-03 19:21:03 +08:00
return ERR_STANDARD_COMPRESSION_FAILED ;
compressed = new UINT8 [ compressedSize ] ;
2014-07-05 20:56:56 +08:00
if ( EfiCompress ( data . constData ( ) , data . size ( ) , compressed , & compressedSize ) ! = ERR_SUCCESS ) {
2014-05-03 19:21:03 +08:00
delete [ ] compressed ;
return ERR_STANDARD_COMPRESSION_FAILED ;
}
compressedData = QByteArray ( ( const char * ) compressed , compressedSize ) ;
2014-11-11 00:48:59 +08:00
// New functions will be trusted here, because another check will reduce performance
2014-05-03 19:21:03 +08:00
delete [ ] compressed ;
return ERR_SUCCESS ;
}
break ;
case COMPRESSION_ALGORITHM_TIANO :
{
2014-11-11 00:48:59 +08:00
// Try legacy function first
UINT32 compressedSize = 0 ;
if ( TianoCompressLegacy ( data . constData ( ) , data . size ( ) , NULL , & compressedSize ) ! = ERR_BUFFER_TOO_SMALL )
return ERR_STANDARD_COMPRESSION_FAILED ;
compressed = new UINT8 [ compressedSize ] ;
if ( TianoCompressLegacy ( data . constData ( ) , data . size ( ) , compressed , & compressedSize ) ! = ERR_SUCCESS ) {
delete [ ] compressed ;
return ERR_STANDARD_COMPRESSION_FAILED ;
}
compressedData = QByteArray ( ( const char * ) compressed , compressedSize ) ;
// Check that compressed data can be decompressed normally
QByteArray decompressed ;
if ( decompress ( compressedData , EFI_STANDARD_COMPRESSION , decompressed , NULL ) = = ERR_SUCCESS
& & decompressed = = data ) {
delete [ ] compressed ;
return ERR_SUCCESS ;
}
delete [ ] compressed ;
// Legacy function failed, use current one
compressedSize = 0 ;
2014-07-05 20:56:56 +08:00
if ( TianoCompress ( data . constData ( ) , data . size ( ) , NULL , & compressedSize ) ! = ERR_BUFFER_TOO_SMALL )
2014-05-03 19:21:03 +08:00
return ERR_STANDARD_COMPRESSION_FAILED ;
compressed = new UINT8 [ compressedSize ] ;
2014-07-05 20:56:56 +08:00
if ( TianoCompress ( data . constData ( ) , data . size ( ) , compressed , & compressedSize ) ! = ERR_SUCCESS ) {
2014-05-03 19:21:03 +08:00
delete [ ] compressed ;
return ERR_STANDARD_COMPRESSION_FAILED ;
}
compressedData = QByteArray ( ( const char * ) compressed , compressedSize ) ;
2014-11-11 00:48:59 +08:00
// New functions will be trusted here, because another check will reduce performance
2014-05-03 19:21:03 +08:00
delete [ ] compressed ;
return ERR_SUCCESS ;
}
break ;
case COMPRESSION_ALGORITHM_LZMA :
{
2014-07-05 20:56:56 +08:00
UINT32 compressedSize = 0 ;
2014-05-03 19:21:03 +08:00
if ( LzmaCompress ( ( const UINT8 * ) data . constData ( ) , data . size ( ) , NULL , & compressedSize ) ! = ERR_BUFFER_TOO_SMALL )
return ERR_CUSTOMIZED_COMPRESSION_FAILED ;
compressed = new UINT8 [ compressedSize ] ;
if ( LzmaCompress ( ( const UINT8 * ) data . constData ( ) , data . size ( ) , compressed , & compressedSize ) ! = ERR_SUCCESS ) {
delete [ ] compressed ;
return ERR_CUSTOMIZED_COMPRESSION_FAILED ;
}
compressedData = QByteArray ( ( const char * ) compressed , compressedSize ) ;
delete [ ] compressed ;
return ERR_SUCCESS ;
}
break ;
case COMPRESSION_ALGORITHM_IMLZMA :
{
2014-07-05 20:56:56 +08:00
UINT32 compressedSize = 0 ;
2014-05-03 19:21:03 +08:00
QByteArray header = data . left ( sizeof ( EFI_COMMON_SECTION_HEADER ) ) ;
2015-01-31 22:00:00 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) header . constData ( ) ;
2014-06-19 11:45:20 +08:00
UINT32 headerSize = sizeOfSectionHeader ( sectionHeader ) ;
2014-05-03 19:21:03 +08:00
header = data . left ( headerSize ) ;
QByteArray newData = data . mid ( headerSize ) ;
2015-01-31 22:00:00 +08:00
if ( LzmaCompress ( ( const UINT8 * ) newData . constData ( ) , newData . size ( ) , NULL , & compressedSize ) ! = ERR_BUFFER_TOO_SMALL )
2014-05-03 19:21:03 +08:00
return ERR_CUSTOMIZED_COMPRESSION_FAILED ;
compressed = new UINT8 [ compressedSize ] ;
2015-01-31 22:00:00 +08:00
if ( LzmaCompress ( ( const UINT8 * ) newData . constData ( ) , newData . size ( ) , compressed , & compressedSize ) ! = ERR_SUCCESS ) {
2014-05-03 19:21:03 +08:00
delete [ ] compressed ;
return ERR_CUSTOMIZED_COMPRESSION_FAILED ;
}
compressedData = header . append ( QByteArray ( ( const char * ) compressed , compressedSize ) ) ;
delete [ ] compressed ;
return ERR_SUCCESS ;
}
break ;
default :
2015-02-06 16:47:19 +08:00
msg ( tr ( " compress: unknown compression algorithm %1 " ) . arg ( algorithm ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_UNKNOWN_COMPRESSION_ALGORITHM ;
}
}
// Construction routines
UINT8 FfsEngine : : constructPadFile ( const QByteArray & guid , const UINT32 size , const UINT8 revision , const UINT8 erasePolarity , QByteArray & pad )
{
if ( size < sizeof ( EFI_FFS_FILE_HEADER ) | | erasePolarity = = ERASE_POLARITY_UNKNOWN )
return ERR_INVALID_PARAMETER ;
pad = QByteArray ( size - guid . size ( ) , erasePolarity = = ERASE_POLARITY_TRUE ? ' \xFF ' : ' \x00 ' ) ;
pad . prepend ( guid ) ;
EFI_FFS_FILE_HEADER * header = ( EFI_FFS_FILE_HEADER * ) pad . data ( ) ;
uint32ToUint24 ( size , header - > Size ) ;
header - > Attributes = 0x00 ;
header - > Type = EFI_FV_FILETYPE_PAD ;
header - > State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID ;
// Invert state bits if erase polarity is true
if ( erasePolarity = = ERASE_POLARITY_TRUE )
header - > State = ~ header - > State ;
// Calculate header checksum
header - > IntegrityCheck . Checksum . Header = 0 ;
header - > IntegrityCheck . Checksum . File = 0 ;
2015-01-31 22:00:00 +08:00
header - > IntegrityCheck . Checksum . Header = calculateChecksum8 ( ( const UINT8 * ) header , sizeof ( EFI_FFS_FILE_HEADER ) - 1 ) ;
2014-05-03 19:21:03 +08:00
// Set data checksum
if ( revision = = 1 )
header - > IntegrityCheck . Checksum . File = FFS_FIXED_CHECKSUM ;
else
header - > IntegrityCheck . Checksum . File = FFS_FIXED_CHECKSUM2 ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : reconstructIntelImage ( const QModelIndex & index , QByteArray & reconstructed )
{
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
UINT8 result ;
// No action
if ( model - > action ( index ) = = Actions : : NoAction ) {
2015-01-31 22:00:00 +08:00
reconstructed = model - > header ( index ) . append ( model - > body ( index ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
// Other supported actions
else if ( model - > action ( index ) = = Actions : : Rebuild ) {
reconstructed . clear ( ) ;
// First child will always be descriptor for this type of image
QByteArray descriptor ;
result = reconstructRegion ( index . child ( 0 , 0 ) , descriptor ) ;
if ( result )
return result ;
reconstructed . append ( descriptor ) ;
2015-01-31 22:00:00 +08:00
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 ) ;
2014-05-03 19:21:03 +08:00
QByteArray gbe ;
UINT32 gbeBegin = calculateRegionOffset ( regionSection - > GbeBase ) ;
UINT32 gbeEnd = gbeBegin + calculateRegionSize ( regionSection - > GbeBase , regionSection - > GbeLimit ) ;
QByteArray me ;
UINT32 meBegin = calculateRegionOffset ( regionSection - > MeBase ) ;
UINT32 meEnd = meBegin + calculateRegionSize ( regionSection - > MeBase , regionSection - > MeLimit ) ;
QByteArray bios ;
UINT32 biosBegin = calculateRegionOffset ( regionSection - > BiosBase ) ;
UINT32 biosEnd = biosBegin + calculateRegionSize ( regionSection - > BiosBase , regionSection - > BiosLimit ) ;
QByteArray pdr ;
UINT32 pdrBegin = calculateRegionOffset ( regionSection - > PdrBase ) ;
UINT32 pdrEnd = pdrBegin + calculateRegionSize ( regionSection - > PdrBase , regionSection - > PdrLimit ) ;
UINT32 offset = descriptor . size ( ) ;
// Reconstruct other regions
2014-07-25 07:59:51 +08:00
char empty = ' \xFF ' ;
2014-05-03 19:21:03 +08:00
for ( int i = 1 ; i < model - > rowCount ( index ) ; i + + ) {
QByteArray region ;
result = reconstructRegion ( index . child ( i , 0 ) , region ) ;
if ( result )
return result ;
2015-02-06 16:47:19 +08:00
UINT8 type = model - > subtype ( index . child ( i , 0 ) ) ;
switch ( type )
2014-05-03 19:21:03 +08:00
{
2015-02-06 16:47:19 +08:00
case Subtypes : : GbeRegion :
2014-05-03 19:21:03 +08:00
gbe = region ;
if ( gbeBegin > offset )
reconstructed . append ( QByteArray ( gbeBegin - offset , empty ) ) ;
reconstructed . append ( gbe ) ;
offset = gbeEnd ;
break ;
2015-02-06 16:47:19 +08:00
case Subtypes : : MeRegion :
2014-05-03 19:21:03 +08:00
me = region ;
if ( meBegin > offset )
reconstructed . append ( QByteArray ( meBegin - offset , empty ) ) ;
reconstructed . append ( me ) ;
offset = meEnd ;
break ;
2015-02-06 16:47:19 +08:00
case Subtypes : : BiosRegion :
2014-05-03 19:21:03 +08:00
bios = region ;
if ( biosBegin > offset )
reconstructed . append ( QByteArray ( biosBegin - offset , empty ) ) ;
reconstructed . append ( bios ) ;
offset = biosEnd ;
break ;
2015-02-06 16:47:19 +08:00
case Subtypes : : PdrRegion :
2014-05-03 19:21:03 +08:00
pdr = region ;
if ( pdrBegin > offset )
reconstructed . append ( QByteArray ( pdrBegin - offset , empty ) ) ;
reconstructed . append ( pdr ) ;
offset = pdrEnd ;
break ;
default :
msg ( tr ( " reconstructIntelImage: unknown region type found " ) , index ) ;
return ERR_INVALID_REGION ;
}
}
if ( ( UINT32 ) model - > body ( index ) . size ( ) > offset )
reconstructed . append ( QByteArray ( ( UINT32 ) model - > body ( index ) . size ( ) - offset , empty ) ) ;
// Check size of reconstructed image, it must be same
if ( reconstructed . size ( ) > model - > body ( index ) . size ( ) ) {
2015-01-31 22:00:00 +08:00
msg ( tr ( " reconstructIntelImage: reconstructed body size %1h (%2) is bigger then original %3h (%4) " )
. hexarg ( reconstructed . size ( ) ) . arg ( reconstructed . size ( ) )
. hexarg ( model - > body ( index ) . size ( ) ) . arg ( model - > body ( index ) . size ( ) ) ,
index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_PARAMETER ;
}
else if ( reconstructed . size ( ) < model - > body ( index ) . size ( ) ) {
2015-01-31 22:00:00 +08:00
msg ( tr ( " reconstructIntelImage: reconstructed body size %1h (%2) is smaller then original %3h (%4) " )
. hexarg ( reconstructed . size ( ) ) . arg ( reconstructed . size ( ) )
. hexarg ( model - > body ( index ) . size ( ) ) . arg ( model - > body ( index ) . size ( ) ) ,
index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_PARAMETER ;
}
// Reconstruction successful
return ERR_SUCCESS ;
}
// All other actions are not supported
return ERR_NOT_IMPLEMENTED ;
}
UINT8 FfsEngine : : reconstructRegion ( const QModelIndex & index , QByteArray & reconstructed )
{
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
UINT8 result ;
// No action
if ( model - > action ( index ) = = Actions : : NoAction ) {
2015-01-31 22:00:00 +08:00
reconstructed = model - > header ( index ) . append ( model - > body ( index ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
else if ( model - > action ( index ) = = Actions : : Remove ) {
reconstructed . clear ( ) ;
return ERR_SUCCESS ;
}
else if ( model - > action ( index ) = = Actions : : Rebuild | |
model - > action ( index ) = = Actions : : Replace ) {
if ( model - > rowCount ( index ) ) {
reconstructed . clear ( ) ;
// Reconstruct children
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
QByteArray child ;
result = reconstruct ( index . child ( i , 0 ) , child ) ;
if ( result )
return result ;
reconstructed . append ( child ) ;
}
}
// Use stored item body
else
reconstructed = model - > body ( index ) ;
// Check size of reconstructed region, it must be same
if ( reconstructed . size ( ) > model - > body ( index ) . size ( ) ) {
2015-01-31 22:00:00 +08:00
msg ( tr ( " reconstructRegion: reconstructed region size %1h (%2) is bigger then original %3h (%4) " )
. hexarg ( reconstructed . size ( ) ) . arg ( reconstructed . size ( ) )
. hexarg ( model - > body ( index ) . size ( ) ) . arg ( reconstructed . size ( ) ) ,
index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_PARAMETER ;
}
else if ( reconstructed . size ( ) < model - > body ( index ) . size ( ) ) {
2015-01-31 22:00:00 +08:00
msg ( tr ( " reconstructRegion: reconstructed region size %1h (%2) is smaller then original %3h (%4) " )
. hexarg ( reconstructed . size ( ) ) . arg ( reconstructed . size ( ) )
. hexarg ( model - > body ( index ) . size ( ) ) . arg ( reconstructed . size ( ) ) ,
index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_PARAMETER ;
}
// Reconstruction successful
reconstructed = model - > header ( index ) . append ( reconstructed ) ;
return ERR_SUCCESS ;
}
// All other actions are not supported
return ERR_NOT_IMPLEMENTED ;
}
UINT8 FfsEngine : : reconstructVolume ( const QModelIndex & index , QByteArray & reconstructed )
{
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
UINT8 result ;
// No action
if ( model - > action ( index ) = = Actions : : NoAction ) {
2015-01-31 22:00:00 +08:00
reconstructed = model - > header ( index ) . append ( model - > body ( index ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
else if ( model - > action ( index ) = = Actions : : Remove ) {
reconstructed . clear ( ) ;
return ERR_SUCCESS ;
}
2015-01-31 22:00:00 +08:00
else if ( model - > action ( index ) = = Actions : : Replace | |
model - > action ( index ) = = Actions : : Rebuild ) {
2014-05-03 19:21:03 +08:00
QByteArray header = model - > header ( index ) ;
2015-02-06 16:47:19 +08:00
QByteArray body = model - > body ( index ) ;
2014-05-03 19:21:03 +08:00
EFI_FIRMWARE_VOLUME_HEADER * volumeHeader = ( EFI_FIRMWARE_VOLUME_HEADER * ) header . data ( ) ;
// Recalculate volume header checksum
volumeHeader - > Checksum = 0 ;
2015-01-31 22:00:00 +08:00
volumeHeader - > Checksum = calculateChecksum16 ( ( const UINT16 * ) volumeHeader , volumeHeader - > HeaderLength ) ;
2014-05-03 19:21:03 +08:00
// Get volume size
2015-02-06 16:47:19 +08:00
UINT32 volumeSize = header . size ( ) + body . size ( ) ;
2014-05-03 19:21:03 +08:00
// Reconstruct volume body
if ( model - > rowCount ( index ) ) {
reconstructed . clear ( ) ;
UINT8 polarity = volumeHeader - > Attributes & EFI_FVB_ERASE_POLARITY ? ERASE_POLARITY_TRUE : ERASE_POLARITY_FALSE ;
char empty = volumeHeader - > Attributes & EFI_FVB_ERASE_POLARITY ? ' \xFF ' : ' \x00 ' ;
// Calculate volume base for volume
UINT32 volumeBase ;
QByteArray file ;
bool baseFound = false ;
// Search for VTF
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
file = model - > header ( index . child ( i , 0 ) ) ;
// VTF found
if ( file . left ( sizeof ( EFI_GUID ) ) = = EFI_FFS_VOLUME_TOP_FILE_GUID ) {
baseFound = true ;
2014-07-25 07:59:51 +08:00
volumeBase = ( UINT32 ) ( 0x100000000 - volumeSize ) ;
2014-05-03 19:21:03 +08:00
break ;
}
}
// Determine if volume is inside compressed item
if ( ! baseFound ) {
// Iterate up to the root, checking for compression type to be other then none
for ( QModelIndex parentIndex = index . parent ( ) ; model - > type ( parentIndex ) ! = Types : : Root ; parentIndex = parentIndex . parent ( ) )
if ( model - > compression ( parentIndex ) ! = COMPRESSION_ALGORITHM_NONE ) {
2014-07-25 07:59:51 +08:00
// No rebase needed for compressed PEI files
baseFound = true ;
volumeBase = 0 ;
break ;
2014-05-03 19:21:03 +08:00
}
}
// Find volume base address using first PEI file in it
if ( ! baseFound ) {
// Search for first PEI-file and use it as base source
UINT32 fileOffset = header . size ( ) ;
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2015-02-06 16:47:19 +08:00
if ( ( model - > subtype ( index . child ( i , 0 ) ) = = EFI_FV_FILETYPE_PEI_CORE | |
model - > subtype ( index . child ( i , 0 ) ) = = EFI_FV_FILETYPE_PEIM | |
model - > subtype ( index . child ( i , 0 ) ) = = EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ) ) {
2014-05-03 19:21:03 +08:00
QModelIndex peiFile = index . child ( i , 0 ) ;
UINT32 sectionOffset = sizeof ( EFI_FFS_FILE_HEADER ) ;
// Search for PE32 or TE section
for ( int j = 0 ; j < model - > rowCount ( peiFile ) ; j + + ) {
2015-02-06 16:47:19 +08:00
if ( model - > subtype ( peiFile . child ( j , 0 ) ) = = EFI_SECTION_PE32 | |
model - > subtype ( peiFile . child ( j , 0 ) ) = = EFI_SECTION_TE ) {
2014-05-03 19:21:03 +08:00
QModelIndex image = peiFile . child ( j , 0 ) ;
// Check for correct action
if ( model - > action ( image ) = = Actions : : Remove | | model - > action ( image ) = = Actions : : Insert )
continue ;
// Calculate relative base address
UINT32 relbase = fileOffset + sectionOffset + model - > header ( image ) . size ( ) ;
// Calculate offset of image relative to file base
UINT32 imagebase ;
result = getBase ( model - > body ( image ) , imagebase ) ;
if ( ! result ) {
// Calculate volume base
volumeBase = imagebase - relbase ;
baseFound = true ;
goto out ;
}
}
sectionOffset + = model - > header ( peiFile . child ( j , 0 ) ) . size ( ) + model - > body ( peiFile . child ( j , 0 ) ) . size ( ) ;
sectionOffset = ALIGN4 ( sectionOffset ) ;
}
}
2015-01-31 22:00:00 +08:00
fileOffset + = model - > header ( index . child ( i , 0 ) ) . size ( ) + model - > body ( index . child ( i , 0 ) ) . size ( ) ;
2014-05-03 19:21:03 +08:00
fileOffset = ALIGN8 ( fileOffset ) ;
}
}
out :
// Do not set volume base
if ( ! baseFound )
volumeBase = 0 ;
// Reconstruct files in volume
UINT32 offset = 0 ;
QByteArray padFileGuid = EFI_FFS_PAD_FILE_GUID ;
QByteArray vtf ;
QModelIndex vtfIndex ;
2015-02-06 16:47:19 +08:00
UINT32 nonUefiDataOffset = 0 ;
QByteArray nonUefiData ;
2014-05-03 19:21:03 +08:00
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2015-02-06 16:47:19 +08:00
// Inside a volume can be files, free space or padding with non-UEFI data
if ( model - > type ( index . child ( i , 0 ) ) = = Types : : File ) { // Next item is a file
// Align to 8 byte boundary
UINT32 alignment = offset % 8 ;
if ( alignment ) {
alignment = 8 - alignment ;
offset + = alignment ;
reconstructed . append ( QByteArray ( alignment , empty ) ) ;
}
2014-05-03 19:21:03 +08:00
2015-02-06 16:47:19 +08:00
// Calculate file base
UINT32 fileBase = volumeBase ? volumeBase + header . size ( ) + offset : 0 ;
2014-05-03 19:21:03 +08:00
2015-02-06 16:47:19 +08:00
// Reconstruct file
result = reconstructFile ( index . child ( i , 0 ) , volumeHeader - > Revision , polarity , fileBase , file ) ;
if ( result )
return result ;
2014-05-03 19:21:03 +08:00
2015-02-06 16:47:19 +08:00
// Empty file
if ( file . isEmpty ( ) )
continue ;
2014-05-03 19:21:03 +08:00
2015-02-06 16:47:19 +08:00
EFI_FFS_FILE_HEADER * fileHeader = ( EFI_FFS_FILE_HEADER * ) file . data ( ) ;
2014-05-03 19:21:03 +08:00
2015-02-06 16:47:19 +08:00
// Pad file
if ( fileHeader - > Type = = EFI_FV_FILETYPE_PAD ) {
padFileGuid = file . left ( sizeof ( EFI_GUID ) ) ;
// Parse non-empty pad file
if ( model - > rowCount ( index . child ( i , 0 ) ) ) {
//TODO: handle it
continue ;
}
// Skip empty pad-file
else
continue ;
}
2014-05-03 19:21:03 +08:00
2015-02-06 16:47:19 +08:00
// Volume Top File
if ( file . left ( sizeof ( EFI_GUID ) ) = = EFI_FFS_VOLUME_TOP_FILE_GUID ) {
vtf = file ;
vtfIndex = index . child ( i , 0 ) ;
continue ;
}
2014-05-03 19:21:03 +08:00
2015-02-06 16:47:19 +08:00
// Normal file
// Ensure correct alignment
UINT8 alignmentPower ;
UINT32 alignmentBase ;
alignmentPower = ffsAlignmentTable [ ( fileHeader - > Attributes & FFS_ATTRIB_DATA_ALIGNMENT ) > > 3 ] ;
alignment = ( UINT32 ) pow ( 2.0 , alignmentPower ) ;
alignmentBase = header . size ( ) + offset + sizeof ( EFI_FFS_FILE_HEADER ) ;
if ( alignmentBase % alignment ) {
// File will be unaligned if added as is, so we must add pad file before it
// Determine pad file size
UINT32 size = alignment - ( alignmentBase % alignment ) ;
// Required padding is smaller then minimal pad file size
while ( size < sizeof ( EFI_FFS_FILE_HEADER ) ) {
size + = alignment ;
}
// Construct pad file
QByteArray pad ;
result = constructPadFile ( padFileGuid , size , volumeHeader - > Revision , polarity , pad ) ;
if ( result )
return result ;
// Append constructed pad file to volume body
reconstructed . append ( pad ) ;
offset + = size ;
2014-05-03 19:21:03 +08:00
}
2015-02-06 16:47:19 +08:00
// Append current file to new volume body
reconstructed . append ( file ) ;
2014-05-03 19:21:03 +08:00
2015-02-06 16:47:19 +08:00
// Change current file offset
offset + = file . size ( ) ;
}
else if ( model - > type ( index . child ( i , 0 ) ) = = Types : : FreeSpace ) { //Next item is a free space
// Some data are located beyond free space
if ( offset + ( UINT32 ) model - > body ( index . child ( i , 0 ) ) . size ( ) < ( UINT32 ) model - > body ( index ) . size ( ) ) {
// Get non-UEFI data and it's offset
nonUefiData = model - > body ( index . child ( i + 1 , 0 ) ) ;
nonUefiDataOffset = body . size ( ) - nonUefiData . size ( ) ;
break ;
}
}
2014-05-03 19:21:03 +08:00
}
2015-02-06 16:47:19 +08:00
// Check volume sanity
if ( ! vtf . isEmpty ( ) & & ! nonUefiData . isEmpty ( ) ) {
msg ( tr ( " reconstructVolume: both VTF and non-UEFI data found in the volume, reconstruction is not possible " ) , index ) ;
return ERR_INVALID_VOLUME ;
}
// Insert VTF or non-UEFI data to it's correct place
if ( ! vtf . isEmpty ( ) ) { // VTF found
2014-05-03 19:21:03 +08:00
// Determine correct VTF offset
2015-02-06 16:47:19 +08:00
UINT32 vtfOffset = model - > body ( index ) . size ( ) - vtf . size ( ) ;
2014-05-03 19:21:03 +08:00
if ( vtfOffset % 8 ) {
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructVolume: wrong size of the Volume Top File " ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_FILE ;
}
// Insert pad file to fill the gap
if ( vtfOffset > offset ) {
// Determine pad file size
UINT32 size = vtfOffset - offset ;
// Construct pad file
QByteArray pad ;
result = constructPadFile ( padFileGuid , size , volumeHeader - > Revision , polarity , pad ) ;
if ( result )
return result ;
// Append constructed pad file to volume body
reconstructed . append ( pad ) ;
}
// No more space left in volume
2015-02-06 16:47:19 +08:00
else if ( offset > vtfOffset ) {
msg ( tr ( " reconstructVolume: no space left to insert VTF, need %1h (%2) byte(s) more " )
. hexarg ( offset - vtfOffset ) . arg ( offset - vtfOffset ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_VOLUME ;
}
// Calculate VTF base
UINT32 vtfBase = volumeBase ? volumeBase + vtfOffset : 0 ;
// Reconstruct VTF again
result = reconstructFile ( vtfIndex , volumeHeader - > Revision , polarity , vtfBase , vtf ) ;
if ( result )
return result ;
// Patch PEI core entry point in VTF
result = patchVtf ( vtf ) ;
if ( result )
return result ;
// Append VTF
reconstructed . append ( vtf ) ;
}
2015-02-06 16:47:19 +08:00
else if ( ! nonUefiData . isEmpty ( ) ) { //Non-UEFI data found
// No space left
if ( offset > nonUefiDataOffset ) {
msg ( tr ( " reconstructVolume: no space left to insert non-UEFI data, need %1h (%2) byte(s) more " )
. hexarg ( offset - nonUefiDataOffset ) . arg ( offset - nonUefiDataOffset ) , index ) ;
return ERR_INVALID_VOLUME ;
}
// Append additional free space
else if ( nonUefiDataOffset > offset ) {
reconstructed . append ( QByteArray ( nonUefiDataOffset - offset , empty ) ) ;
}
// Append VTF
reconstructed . append ( nonUefiData ) ;
}
2014-05-03 19:21:03 +08:00
else {
// Fill the rest of volume space with empty char
2015-02-06 16:47:19 +08:00
if ( body . size ( ) > reconstructed . size ( ) ) {
2014-05-03 19:21:03 +08:00
// Fill volume end with empty char
2015-02-06 16:47:19 +08:00
reconstructed . append ( QByteArray ( body . size ( ) - reconstructed . size ( ) , empty ) ) ;
2014-05-03 19:21:03 +08:00
}
2015-02-06 16:47:19 +08:00
else if ( body . size ( ) < reconstructed . size ( ) ) {
2014-05-03 19:21:03 +08:00
// Check if volume can be grown
2015-02-06 16:47:19 +08:00
// Root volume can't be grown
2014-05-03 19:21:03 +08:00
UINT8 parentType = model - > type ( index . parent ( ) ) ;
if ( parentType ! = Types : : File & & parentType ! = Types : : Section ) {
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructVolume: root volume can't be grown " ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_VOLUME ;
}
// Grow volume to fit new body
UINT32 newSize = header . size ( ) + reconstructed . size ( ) ;
result = growVolume ( header , volumeSize , newSize ) ;
if ( result )
return result ;
// Fill volume end with empty char
reconstructed . append ( QByteArray ( newSize - header . size ( ) - reconstructed . size ( ) , empty ) ) ;
volumeSize = newSize ;
}
}
// Check new volume size
if ( ( UINT32 ) ( header . size ( ) + reconstructed . size ( ) ) > volumeSize )
{
msg ( tr ( " reconstructVolume: volume grow failed " ) , index ) ;
return ERR_INVALID_VOLUME ;
}
}
// Use current volume body
else
reconstructed = model - > body ( index ) ;
// Reconstruction successful
reconstructed = header . append ( reconstructed ) ;
2015-01-26 06:55:05 +08:00
// Recalculate CRC32 in ZeroVector, if needed
2015-02-06 16:47:19 +08:00
const PARSING_DATA * pdata = ( const PARSING_DATA * ) model - > parsingData ( index ) . constData ( ) ;
2015-02-07 00:46:26 +08:00
if ( pdata - > Type = = VolumeParsingData & & pdata - > Data . Volume . HasZeroVectorCRC ) {
2015-01-26 06:55:05 +08:00
// Get current CRC32 value from volume header
2015-01-31 22:00:00 +08:00
const UINT32 current = * ( const UINT32 * ) ( reconstructed . constData ( ) + 8 ) ;
2015-01-26 06:55:05 +08:00
// Calculate new value
2015-01-31 22:00:00 +08:00
UINT32 crc = crc32 ( 0 , ( const UINT8 * ) reconstructed . constData ( ) + volumeHeader - > HeaderLength , reconstructed . size ( ) - volumeHeader - > HeaderLength ) ;
2015-01-26 06:55:05 +08:00
// Update the value
if ( current ! = crc ) {
* ( UINT32 * ) ( reconstructed . data ( ) + 8 ) = crc ;
// Recalculate header checksum again
volumeHeader = ( EFI_FIRMWARE_VOLUME_HEADER * ) reconstructed . data ( ) ;
volumeHeader - > Checksum = 0 ;
2015-01-31 22:00:00 +08:00
volumeHeader - > Checksum = calculateChecksum16 ( ( const UINT16 * ) volumeHeader , volumeHeader - > HeaderLength ) ;
2015-01-26 06:55:05 +08:00
}
}
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
// All other actions are not supported
return ERR_NOT_IMPLEMENTED ;
}
UINT8 FfsEngine : : reconstructFile ( const QModelIndex & index , const UINT8 revision , const UINT8 erasePolarity , const UINT32 base , QByteArray & reconstructed )
{
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
UINT8 result ;
// No action
if ( model - > action ( index ) = = Actions : : NoAction ) {
2015-01-31 22:00:00 +08:00
reconstructed = model - > header ( index ) . append ( model - > body ( index ) ) ;
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) model - > header ( index ) . constData ( ) ;
// Append tail, if needed
if ( fileHeader - > Attributes & FFS_ATTRIB_TAIL_PRESENT ) {
UINT8 ht = ~ fileHeader - > IntegrityCheck . Checksum . Header ;
UINT8 ft = ~ fileHeader - > IntegrityCheck . Checksum . File ;
reconstructed . append ( ht ) . append ( ft ) ;
}
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
else if ( model - > action ( index ) = = Actions : : Remove ) {
reconstructed . clear ( ) ;
return ERR_SUCCESS ;
}
else if ( model - > action ( index ) = = Actions : : Insert | |
model - > action ( index ) = = Actions : : Replace | |
model - > action ( index ) = = Actions : : Rebuild ) {
QByteArray header = model - > header ( index ) ;
EFI_FFS_FILE_HEADER * fileHeader = ( EFI_FFS_FILE_HEADER * ) header . data ( ) ;
// Check erase polarity
if ( erasePolarity = = ERASE_POLARITY_UNKNOWN ) {
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructFile: unknown erase polarity " ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_PARAMETER ;
}
// Check file state
// Invert it first if erase polarity is true
UINT8 state = fileHeader - > State ;
if ( erasePolarity = = ERASE_POLARITY_TRUE )
state = ~ state ;
// Order of this checks must be preserved
// Check file to have valid state, or delete it otherwise
if ( state & EFI_FILE_HEADER_INVALID ) {
// File marked to have invalid header and must be deleted
// Do not add anything to queue
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructFile: file is HEADER_INVALID state, and will be removed from reconstructed image " ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
else if ( state & EFI_FILE_DELETED ) {
// File marked to have been deleted form and must be deleted
// Do not add anything to queue
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructFile: file is in DELETED state, and will be removed from reconstructed image " ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
else if ( state & EFI_FILE_MARKED_FOR_UPDATE ) {
// File is marked for update, the mark must be removed
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructFile: file's MARKED_FOR_UPDATE state cleared " ) , index ) ;
2014-05-03 19:21:03 +08:00
}
else if ( state & EFI_FILE_DATA_VALID ) {
// File is in good condition, reconstruct it
}
else if ( state & EFI_FILE_HEADER_VALID ) {
// Header is valid, but data is not, so file must be deleted
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructFile: file is in HEADER_VALID (but not in DATA_VALID) state, and will be removed from reconstructed image " ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
else if ( state & EFI_FILE_HEADER_CONSTRUCTION ) {
// Header construction not finished, so file must be deleted
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructFile: file is in HEADER_CONSTRUCTION (but not in DATA_VALID) state, and will be removed from reconstructed image " ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
// Reconstruct file body
if ( model - > rowCount ( index ) ) {
reconstructed . clear ( ) ;
// Construct new file body
// File contains raw data, must be parsed as region
2015-02-06 16:47:19 +08:00
if ( model - > subtype ( index ) = = EFI_FV_FILETYPE_ALL | | model - > subtype ( index ) = = EFI_FV_FILETYPE_RAW ) {
2014-05-03 19:21:03 +08:00
result = reconstructRegion ( index , reconstructed ) ;
if ( result )
return result ;
}
// File contains sections
else {
UINT32 offset = 0 ;
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
// Align to 4 byte boundary
UINT8 alignment = offset % 4 ;
if ( alignment ) {
alignment = 4 - alignment ;
offset + = alignment ;
reconstructed . append ( QByteArray ( alignment , ' \x00 ' ) ) ;
}
// Calculate section base
2014-07-25 07:59:51 +08:00
UINT32 sectionBase = base ? base + sizeof ( EFI_FFS_FILE_HEADER ) + offset : 0 ;
2014-05-03 19:21:03 +08:00
// Reconstruct section
QByteArray section ;
result = reconstructSection ( index . child ( i , 0 ) , sectionBase , section ) ;
if ( result )
return result ;
// Check for empty section
if ( section . isEmpty ( ) )
continue ;
// Append current section to new file body
reconstructed . append ( section ) ;
// Change current file offset
offset + = section . size ( ) ;
}
}
// Correct file size
2015-02-06 16:47:19 +08:00
UINT8 tailSize = ( revision = = 1 & & ( fileHeader - > Attributes & FFS_ATTRIB_TAIL_PRESENT ) ) ? sizeof ( UINT16 ) : 0 ;
2014-05-03 19:21:03 +08:00
2014-07-25 07:59:51 +08:00
uint32ToUint24 ( sizeof ( EFI_FFS_FILE_HEADER ) + reconstructed . size ( ) + tailSize , fileHeader - > Size ) ;
2014-05-03 19:21:03 +08:00
// Recalculate header checksum
fileHeader - > IntegrityCheck . Checksum . Header = 0 ;
fileHeader - > IntegrityCheck . Checksum . File = 0 ;
2015-01-31 22:00:00 +08:00
fileHeader - > IntegrityCheck . Checksum . Header = calculateChecksum8 ( ( const UINT8 * ) fileHeader , sizeof ( EFI_FFS_FILE_HEADER ) - 1 ) ;
2014-05-03 19:21:03 +08:00
}
// Use current file body
else
reconstructed = model - > body ( index ) ;
// Recalculate data checksum, if needed
if ( fileHeader - > Attributes & FFS_ATTRIB_CHECKSUM ) {
2015-01-31 22:00:00 +08:00
fileHeader - > IntegrityCheck . Checksum . File = calculateChecksum8 ( ( const UINT8 * ) reconstructed . constData ( ) , reconstructed . size ( ) ) ;
2014-05-03 19:21:03 +08:00
}
else if ( revision = = 1 )
fileHeader - > IntegrityCheck . Checksum . File = FFS_FIXED_CHECKSUM ;
else
fileHeader - > IntegrityCheck . Checksum . File = FFS_FIXED_CHECKSUM2 ;
// Append tail, if needed
if ( fileHeader - > Attributes & FFS_ATTRIB_TAIL_PRESENT ) {
UINT8 ht = ~ fileHeader - > IntegrityCheck . Checksum . Header ;
UINT8 ft = ~ fileHeader - > IntegrityCheck . Checksum . File ;
reconstructed . append ( ht ) . append ( ft ) ;
}
// Set file state
state = EFI_FILE_DATA_VALID | EFI_FILE_HEADER_VALID | EFI_FILE_HEADER_CONSTRUCTION ;
if ( erasePolarity = = ERASE_POLARITY_TRUE )
state = ~ state ;
fileHeader - > State = state ;
// Reconstruction successful
reconstructed = header . append ( reconstructed ) ;
return ERR_SUCCESS ;
}
// All other actions are not supported
return ERR_NOT_IMPLEMENTED ;
}
UINT8 FfsEngine : : reconstructSection ( const QModelIndex & index , const UINT32 base , QByteArray & reconstructed )
{
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
UINT8 result ;
// No action
if ( model - > action ( index ) = = Actions : : NoAction ) {
2015-01-31 22:00:00 +08:00
reconstructed = model - > header ( index ) . append ( model - > body ( index ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
else if ( model - > action ( index ) = = Actions : : Remove ) {
reconstructed . clear ( ) ;
return ERR_SUCCESS ;
}
else if ( model - > action ( index ) = = Actions : : Insert | |
model - > action ( index ) = = Actions : : Replace | |
model - > action ( index ) = = Actions : : Rebuild | |
model - > action ( index ) = = Actions : : Rebase ) {
QByteArray header = model - > header ( index ) ;
EFI_COMMON_SECTION_HEADER * commonHeader = ( EFI_COMMON_SECTION_HEADER * ) header . data ( ) ;
// Reconstruct section with children
if ( model - > rowCount ( index ) ) {
reconstructed . clear ( ) ;
// Construct new section body
UINT32 offset = 0 ;
// Reconstruct section body
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
// Align to 4 byte boundary
UINT8 alignment = offset % 4 ;
if ( alignment ) {
alignment = 4 - alignment ;
offset + = alignment ;
reconstructed . append ( QByteArray ( alignment , ' \x00 ' ) ) ;
}
// Reconstruct subsections
QByteArray section ;
result = reconstruct ( index . child ( i , 0 ) , section ) ;
if ( result )
return result ;
// Check for empty queue
if ( section . isEmpty ( ) )
continue ;
// Append current subsection to new section body
reconstructed . append ( section ) ;
// Change current file offset
offset + = section . size ( ) ;
}
// Only this 2 sections can have compressed body
2015-02-06 16:47:19 +08:00
if ( model - > subtype ( index ) = = EFI_SECTION_COMPRESSION ) {
2014-05-03 19:21:03 +08:00
EFI_COMPRESSION_SECTION * compessionHeader = ( EFI_COMPRESSION_SECTION * ) header . data ( ) ;
// Set new uncompressed size
compessionHeader - > UncompressedLength = reconstructed . size ( ) ;
// Compress new section body
QByteArray compressed ;
result = compress ( reconstructed , model - > compression ( index ) , compressed ) ;
if ( result )
return result ;
// Correct compression type
if ( model - > compression ( index ) = = COMPRESSION_ALGORITHM_NONE )
compessionHeader - > CompressionType = EFI_NOT_COMPRESSED ;
else if ( model - > compression ( index ) = = COMPRESSION_ALGORITHM_LZMA | | model - > compression ( index ) = = COMPRESSION_ALGORITHM_IMLZMA )
compessionHeader - > CompressionType = EFI_CUSTOMIZED_COMPRESSION ;
else if ( model - > compression ( index ) = = COMPRESSION_ALGORITHM_EFI11 | | model - > compression ( index ) = = COMPRESSION_ALGORITHM_TIANO )
compessionHeader - > CompressionType = EFI_STANDARD_COMPRESSION ;
else
return ERR_UNKNOWN_COMPRESSION_ALGORITHM ;
// Replace new section body
reconstructed = compressed ;
}
2015-02-06 16:47:19 +08:00
else if ( model - > subtype ( index ) = = EFI_SECTION_GUID_DEFINED ) {
2014-05-03 19:21:03 +08:00
EFI_GUID_DEFINED_SECTION * guidDefinedHeader = ( EFI_GUID_DEFINED_SECTION * ) header . data ( ) ;
// Compress new section body
QByteArray compressed ;
result = compress ( reconstructed , model - > compression ( index ) , compressed ) ;
if ( result )
return result ;
// Check for authentication status valid attribute
if ( guidDefinedHeader - > Attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID ) {
// CRC32 section
if ( QByteArray ( ( const char * ) & guidDefinedHeader - > SectionDefinitionGuid , sizeof ( EFI_GUID ) ) = = EFI_GUIDED_SECTION_CRC32 ) {
// Calculate CRC32 of section data
2015-01-31 22:00:00 +08:00
UINT32 crc = crc32 ( 0 , ( const UINT8 * ) compressed . constData ( ) , compressed . size ( ) ) ;
2014-07-25 07:59:51 +08:00
// Store new CRC32
2014-05-03 19:21:03 +08:00
* ( UINT32 * ) ( header . data ( ) + sizeof ( EFI_GUID_DEFINED_SECTION ) ) = crc ;
}
else {
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructSection: GUID defined section authentication info can become invalid " )
2014-05-03 19:21:03 +08:00
. arg ( guidToQString ( guidDefinedHeader - > SectionDefinitionGuid ) ) , index ) ;
}
}
2014-11-08 19:40:06 +08:00
// Check for Intel signed section
if ( guidDefinedHeader - > Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED
2015-02-13 03:51:23 +08:00
& & QByteArray ( ( const char * ) & guidDefinedHeader - > SectionDefinitionGuid , sizeof ( EFI_GUID ) ) = = EFI_FIRMWARE_CONTENTS_SIGNED_GUID ) {
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstructSection: GUID defined section signature can become invalid " )
. arg ( guidToQString ( guidDefinedHeader - > SectionDefinitionGuid ) ) , index ) ;
}
2014-05-03 19:21:03 +08:00
// Replace new section body
reconstructed = compressed ;
}
else if ( model - > compression ( index ) ! = COMPRESSION_ALGORITHM_NONE ) {
msg ( tr ( " reconstructSection: incorrectly required compression for section of type %1 " )
2015-02-06 16:47:19 +08:00
. arg ( model - > subtype ( index ) ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_INVALID_SECTION ;
}
// Correct section size
uint32ToUint24 ( header . size ( ) + reconstructed . size ( ) , commonHeader - > Size ) ;
}
// Leaf section
else
reconstructed = model - > body ( index ) ;
// Rebase PE32 or TE image, if needed
2015-02-06 16:47:19 +08:00
if ( ( model - > subtype ( index ) = = EFI_SECTION_PE32 | | model - > subtype ( index ) = = EFI_SECTION_TE ) & &
( model - > subtype ( index . parent ( ) ) = = EFI_FV_FILETYPE_PEI_CORE | |
model - > subtype ( index . parent ( ) ) = = EFI_FV_FILETYPE_PEIM | |
model - > subtype ( index . parent ( ) ) = = EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ) ) {
2015-01-31 22:00:00 +08:00
UINT16 teFixup = 0 ;
//TODO: add proper handling
2015-02-06 16:47:19 +08:00
/*if (model->subtype(index) == EFI_SECTION_TE) {
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_TE_HEADER * teHeader = ( const EFI_IMAGE_TE_HEADER * ) model - > body ( index ) . constData ( ) ;
teFixup = teHeader - > StrippedSize - sizeof ( EFI_IMAGE_TE_HEADER ) ;
} */
2014-05-03 19:21:03 +08:00
if ( base ) {
2015-01-31 22:00:00 +08:00
result = rebase ( reconstructed , base - teFixup + header . size ( ) ) ;
2014-05-03 19:21:03 +08:00
if ( result ) {
msg ( tr ( " reconstructSection: executable section rebase failed " ) , index ) ;
return result ;
}
// Special case of PEI Core rebase
2015-02-06 16:47:19 +08:00
if ( model - > subtype ( index . parent ( ) ) = = EFI_FV_FILETYPE_PEI_CORE ) {
2014-05-03 19:21:03 +08:00
result = getEntryPoint ( reconstructed , newPeiCoreEntryPoint ) ;
if ( result )
msg ( tr ( " reconstructSection: can't get entry point of PEI core " ) , index ) ;
}
}
}
// Reconstruction successful
reconstructed = header . append ( reconstructed ) ;
2014-07-05 20:56:56 +08:00
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
// All other actions are not supported
return ERR_NOT_IMPLEMENTED ;
}
UINT8 FfsEngine : : reconstruct ( const QModelIndex & index , QByteArray & reconstructed )
{
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
UINT8 result ;
switch ( model - > type ( index ) ) {
case Types : : Image :
2015-02-06 16:47:19 +08:00
if ( model - > subtype ( index ) = = Subtypes : : IntelImage ) {
2014-05-03 19:21:03 +08:00
result = reconstructIntelImage ( index , reconstructed ) ;
if ( result )
return result ;
}
else {
//Other images types can be reconstructed like regions
result = reconstructRegion ( index , reconstructed ) ;
if ( result )
return result ;
}
break ;
case Types : : Capsule :
// Capsules can be reconstructed like regions
result = reconstructRegion ( index , reconstructed ) ;
if ( result )
return result ;
break ;
case Types : : Region :
result = reconstructRegion ( index , reconstructed ) ;
if ( result )
return result ;
break ;
case Types : : Padding :
// No reconstruction needed
2015-01-31 22:00:00 +08:00
reconstructed = model - > header ( index ) . append ( model - > body ( index ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
break ;
case Types : : Volume :
result = reconstructVolume ( index , reconstructed ) ;
if ( result )
return result ;
break ;
case Types : : File : //Must not be called that way
msg ( tr ( " reconstruct: call of generic function is not supported for files " ) . arg ( model - > type ( index ) ) , index ) ;
return ERR_GENERIC_CALL_NOT_SUPPORTED ;
break ;
case Types : : Section :
result = reconstructSection ( index , 0 , reconstructed ) ;
if ( result )
return result ;
break ;
default :
2014-11-08 19:40:06 +08:00
msg ( tr ( " reconstruct: unknown item type %1 " ) . arg ( model - > type ( index ) ) , index ) ;
2014-05-03 19:21:03 +08:00
return ERR_UNKNOWN_ITEM_TYPE ;
}
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : growVolume ( QByteArray & header , const UINT32 size , UINT32 & newSize )
{
// Adjust new size to be representable by current FvBlockMap
EFI_FIRMWARE_VOLUME_HEADER * volumeHeader = ( EFI_FIRMWARE_VOLUME_HEADER * ) header . data ( ) ;
EFI_FV_BLOCK_MAP_ENTRY * blockMap = ( EFI_FV_BLOCK_MAP_ENTRY * ) ( header . data ( ) + sizeof ( EFI_FIRMWARE_VOLUME_HEADER ) ) ;
// Get block map size
UINT32 blockMapSize = volumeHeader - > HeaderLength - sizeof ( EFI_FIRMWARE_VOLUME_HEADER ) ;
if ( blockMapSize % sizeof ( EFI_FV_BLOCK_MAP_ENTRY ) )
return ERR_INVALID_VOLUME ;
UINT32 blockMapCount = blockMapSize / sizeof ( EFI_FV_BLOCK_MAP_ENTRY ) ;
// Check blockMap validity
if ( blockMap [ blockMapCount - 1 ] . NumBlocks ! = 0 | | blockMap [ blockMapCount - 1 ] . Length ! = 0 )
return ERR_INVALID_VOLUME ;
// Case of complex blockMap
if ( blockMapCount > 2 )
return ERR_COMPLEX_BLOCK_MAP ;
// Calculate new size
if ( newSize < = size )
return ERR_INVALID_PARAMETER ;
newSize + = blockMap [ 0 ] . Length - newSize % blockMap [ 0 ] . Length ;
// Recalculate number of blocks
blockMap [ 0 ] . NumBlocks = newSize / blockMap [ 0 ] . Length ;
// Set new volume size
volumeHeader - > FvLength = 0 ;
for ( UINT8 i = 0 ; i < blockMapCount ; i + + ) {
volumeHeader - > FvLength + = blockMap [ i ] . NumBlocks * blockMap [ i ] . Length ;
}
// Recalculate volume header checksum
volumeHeader - > Checksum = 0 ;
2015-01-31 22:00:00 +08:00
volumeHeader - > Checksum = calculateChecksum16 ( ( const UINT16 * ) volumeHeader , volumeHeader - > HeaderLength ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : reconstructImageFile ( QByteArray & reconstructed )
{
return reconstruct ( model - > index ( 0 , 0 ) , reconstructed ) ;
}
// Search routines
2014-07-14 06:38:34 +08:00
UINT8 FfsEngine : : findHexPattern ( const QModelIndex & index , const QByteArray & hexPattern , const UINT8 mode )
2014-05-03 19:21:03 +08:00
{
2014-12-19 16:20:36 +08:00
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
2014-07-14 06:38:34 +08:00
if ( hexPattern . isEmpty ( ) )
2014-05-03 19:21:03 +08:00
return ERR_INVALID_PARAMETER ;
2014-12-19 16:20:36 +08:00
// Check for "all substrings" pattern
if ( hexPattern . count ( ' . ' ) = = hexPattern . length ( ) )
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
bool hasChildren = ( model - > rowCount ( index ) > 0 ) ;
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2014-07-14 06:38:34 +08:00
findHexPattern ( index . child ( i , index . column ( ) ) , hexPattern , mode ) ;
2014-05-03 19:21:03 +08:00
}
QByteArray data ;
if ( hasChildren ) {
if ( mode ! = SEARCH_MODE_BODY )
data = model - > header ( index ) ;
}
else {
if ( mode = = SEARCH_MODE_HEADER )
2014-12-19 16:20:36 +08:00
data . append ( model - > header ( index ) ) ;
2014-05-03 19:21:03 +08:00
else if ( mode = = SEARCH_MODE_BODY )
data . append ( model - > body ( index ) ) ;
else
2015-01-31 22:00:00 +08:00
data . append ( model - > header ( index ) ) . append ( model - > body ( index ) ) ;
2014-05-03 19:21:03 +08:00
}
2014-07-14 06:38:34 +08:00
QString hexBody = QString ( data . toHex ( ) ) ;
QRegExp regexp = QRegExp ( QString ( hexPattern ) , Qt : : CaseInsensitive ) ;
INT32 offset = regexp . indexIn ( hexBody ) ;
while ( offset > = 0 ) {
if ( offset % 2 = = 0 ) {
2015-01-31 22:00:00 +08:00
msg ( tr ( " Hex pattern \" %1 \" found as \" %2 \" in %3 at %4-offset %5h " )
2014-07-14 06:38:34 +08:00
. arg ( QString ( hexPattern ) )
2014-11-09 05:24:53 +08:00
. arg ( hexBody . mid ( offset , hexPattern . length ( ) ) . toUpper ( ) )
2015-01-31 22:00:00 +08:00
. arg ( model - > name ( index ) )
2014-07-14 06:38:34 +08:00
. arg ( mode = = SEARCH_MODE_BODY ? tr ( " body " ) : tr ( " header " ) )
2015-01-31 22:00:00 +08:00
. hexarg ( offset / 2 ) ,
2014-07-14 06:38:34 +08:00
index ) ;
}
offset = regexp . indexIn ( hexBody , offset + 1 ) ;
}
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : findGuidPattern ( const QModelIndex & index , const QByteArray & guidPattern , const UINT8 mode )
{
if ( guidPattern . isEmpty ( ) )
return ERR_INVALID_PARAMETER ;
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
bool hasChildren = ( model - > rowCount ( index ) > 0 ) ;
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
findGuidPattern ( index . child ( i , index . column ( ) ) , guidPattern , mode ) ;
}
QByteArray data ;
if ( hasChildren ) {
if ( mode ! = SEARCH_MODE_BODY )
data = model - > header ( index ) ;
}
else {
if ( mode = = SEARCH_MODE_HEADER )
2014-12-19 16:20:36 +08:00
data . append ( model - > header ( index ) ) ;
2014-07-14 06:38:34 +08:00
else if ( mode = = SEARCH_MODE_BODY )
data . append ( model - > body ( index ) ) ;
else
2015-01-31 22:00:00 +08:00
data . append ( model - > header ( index ) ) . append ( model - > body ( index ) ) ;
2014-07-14 06:38:34 +08:00
}
QString hexBody = QString ( data . toHex ( ) ) ;
QList < QByteArray > list = guidPattern . split ( ' - ' ) ;
if ( list . count ( ) ! = 5 )
return ERR_INVALID_PARAMETER ;
2014-07-25 07:59:51 +08:00
2014-07-14 06:38:34 +08:00
QByteArray hexPattern ;
// Reverse first GUID block
hexPattern . append ( list . at ( 0 ) . mid ( 6 , 2 ) ) ;
hexPattern . append ( list . at ( 0 ) . mid ( 4 , 2 ) ) ;
hexPattern . append ( list . at ( 0 ) . mid ( 2 , 2 ) ) ;
hexPattern . append ( list . at ( 0 ) . mid ( 0 , 2 ) ) ;
// Reverse second GUID block
hexPattern . append ( list . at ( 1 ) . mid ( 2 , 2 ) ) ;
hexPattern . append ( list . at ( 1 ) . mid ( 0 , 2 ) ) ;
// Reverse third GUID block
hexPattern . append ( list . at ( 2 ) . mid ( 2 , 2 ) ) ;
hexPattern . append ( list . at ( 2 ) . mid ( 0 , 2 ) ) ;
// Append fourth and fifth GUID blocks as is
hexPattern . append ( list . at ( 3 ) ) . append ( list . at ( 4 ) ) ;
// Check for "all substrings" pattern
if ( hexPattern . count ( ' . ' ) = = hexPattern . length ( ) )
return ERR_SUCCESS ;
QRegExp regexp = QRegExp ( QString ( hexPattern ) , Qt : : CaseInsensitive ) ;
INT32 offset = regexp . indexIn ( hexBody ) ;
while ( offset > = 0 ) {
if ( offset % 2 = = 0 ) {
2015-01-31 22:00:00 +08:00
msg ( tr ( " GUID pattern \" %1 \" found as \" %2 \" in %3 at %4-offset %5h " )
2014-07-14 06:38:34 +08:00
. arg ( QString ( guidPattern ) )
2014-11-09 05:24:53 +08:00
. arg ( hexBody . mid ( offset , hexPattern . length ( ) ) . toUpper ( ) )
2015-01-31 22:00:00 +08:00
. arg ( model - > name ( index ) )
2014-07-14 06:38:34 +08:00
. arg ( mode = = SEARCH_MODE_BODY ? tr ( " body " ) : tr ( " header " ) )
2015-01-31 22:00:00 +08:00
. hexarg ( offset / 2 ) ,
2014-07-14 06:38:34 +08:00
index ) ;
}
offset = regexp . indexIn ( hexBody , offset + 1 ) ;
2014-05-03 19:21:03 +08:00
}
return ERR_SUCCESS ;
}
2014-07-09 15:20:13 +08:00
UINT8 FfsEngine : : findTextPattern ( const QModelIndex & index , const QString & pattern , const bool unicode , const Qt : : CaseSensitivity caseSensitive )
2014-05-03 19:21:03 +08:00
{
if ( pattern . isEmpty ( ) )
return ERR_INVALID_PARAMETER ;
if ( ! index . isValid ( ) )
return ERR_SUCCESS ;
bool hasChildren = ( model - > rowCount ( index ) > 0 ) ;
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2014-07-09 15:20:13 +08:00
findTextPattern ( index . child ( i , index . column ( ) ) , pattern , unicode , caseSensitive ) ;
2014-05-03 19:21:03 +08:00
}
if ( hasChildren )
return ERR_SUCCESS ;
QString data ;
if ( unicode )
data = QString : : fromUtf16 ( ( const ushort * ) model - > body ( index ) . data ( ) , model - > body ( index ) . length ( ) / 2 ) ;
else
data = QString : : fromLatin1 ( ( const char * ) model - > body ( index ) . data ( ) , model - > body ( index ) . length ( ) ) ;
int offset = - 1 ;
while ( ( offset = data . indexOf ( pattern , offset + 1 , caseSensitive ) ) > = 0 ) {
2015-01-31 22:00:00 +08:00
msg ( tr ( " %1 text \" %2 \" found in %3 at offset %4h " )
2014-05-03 19:21:03 +08:00
. arg ( unicode ? " Unicode " : " ASCII " )
. arg ( pattern )
2015-01-31 22:00:00 +08:00
. arg ( model - > name ( index ) )
. hexarg ( unicode ? offset * 2 : offset ) ,
2014-05-03 19:21:03 +08:00
index ) ;
}
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : rebase ( QByteArray & executable , const UINT32 base )
{
UINT32 delta ; // Difference between old and new base addresses
UINT32 relocOffset ; // Offset of relocation region
UINT32 relocSize ; // Size of relocation region
UINT32 teFixup = 0 ; // Bytes removed form PE header for TE images
// Copy input data to local storage
QByteArray file = executable ;
// Populate DOS header
EFI_IMAGE_DOS_HEADER * dosHeader = ( EFI_IMAGE_DOS_HEADER * ) file . data ( ) ;
// Check signature
if ( dosHeader - > e_magic = = EFI_IMAGE_DOS_SIGNATURE ) {
UINT32 offset = dosHeader - > e_lfanew ;
EFI_IMAGE_PE_HEADER * peHeader = ( EFI_IMAGE_PE_HEADER * ) ( file . data ( ) + offset ) ;
if ( peHeader - > Signature ! = EFI_IMAGE_PE_SIGNATURE )
return ERR_UNKNOWN_IMAGE_TYPE ;
offset + = sizeof ( EFI_IMAGE_PE_HEADER ) ;
// Skip file header
offset + = sizeof ( EFI_IMAGE_FILE_HEADER ) ;
// Check optional header magic
UINT16 magic = * ( UINT16 * ) ( file . data ( ) + offset ) ;
if ( magic = = EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC ) {
EFI_IMAGE_OPTIONAL_HEADER32 * optHeader = ( EFI_IMAGE_OPTIONAL_HEADER32 * ) ( file . data ( ) + offset ) ;
delta = base - optHeader - > ImageBase ;
if ( ! delta )
// No need to rebase
return ERR_SUCCESS ;
relocOffset = optHeader - > DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC ] . VirtualAddress ;
relocSize = optHeader - > DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC ] . Size ;
// Set new base
optHeader - > ImageBase = base ;
}
else if ( magic = = EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC ) {
EFI_IMAGE_OPTIONAL_HEADER64 * optHeader = ( EFI_IMAGE_OPTIONAL_HEADER64 * ) ( file . data ( ) + offset ) ;
delta = base - optHeader - > ImageBase ;
if ( ! delta )
// No need to rebase
return ERR_SUCCESS ;
relocOffset = optHeader - > DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC ] . VirtualAddress ;
relocSize = optHeader - > DataDirectory [ EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC ] . Size ;
// Set new base
optHeader - > ImageBase = base ;
}
else
return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE ;
}
else if ( dosHeader - > e_magic = = EFI_IMAGE_TE_SIGNATURE ) {
// Populate TE header
EFI_IMAGE_TE_HEADER * teHeader = ( EFI_IMAGE_TE_HEADER * ) file . data ( ) ;
delta = base - teHeader - > ImageBase ;
if ( ! delta )
// No need to rebase
return ERR_SUCCESS ;
relocOffset = teHeader - > DataDirectory [ EFI_IMAGE_TE_DIRECTORY_ENTRY_BASERELOC ] . VirtualAddress ;
teFixup = teHeader - > StrippedSize - sizeof ( EFI_IMAGE_TE_HEADER ) ;
relocSize = teHeader - > DataDirectory [ EFI_IMAGE_TE_DIRECTORY_ENTRY_BASERELOC ] . Size ;
// Set new base
teHeader - > ImageBase = base ;
}
else
return ERR_UNKNOWN_IMAGE_TYPE ;
// No relocations
if ( relocOffset = = 0 ) {
// No need to fix relocations
executable = file ;
return ERR_SUCCESS ;
}
2014-12-19 16:20:36 +08:00
EFI_IMAGE_BASE_RELOCATION * RelocBase ;
EFI_IMAGE_BASE_RELOCATION * RelocBaseEnd ;
UINT16 * Reloc ;
UINT16 * RelocEnd ;
UINT16 * F16 ;
UINT32 * F32 ;
UINT64 * F64 ;
2014-05-03 19:21:03 +08:00
// Run the whole relocation block
RelocBase = ( EFI_IMAGE_BASE_RELOCATION * ) ( file . data ( ) + relocOffset - teFixup ) ;
RelocBaseEnd = ( EFI_IMAGE_BASE_RELOCATION * ) ( file . data ( ) + relocOffset - teFixup + relocSize ) ;
while ( RelocBase < RelocBaseEnd ) {
Reloc = ( UINT16 * ) ( ( UINT8 * ) RelocBase + sizeof ( EFI_IMAGE_BASE_RELOCATION ) ) ;
RelocEnd = ( UINT16 * ) ( ( UINT8 * ) RelocBase + RelocBase - > SizeOfBlock ) ;
// Run this relocation record
while ( Reloc < RelocEnd ) {
UINT8 * data = ( UINT8 * ) ( file . data ( ) + RelocBase - > VirtualAddress - teFixup + ( * Reloc & 0x0FFF ) ) ;
switch ( ( * Reloc ) > > 12 ) {
case EFI_IMAGE_REL_BASED_ABSOLUTE :
// Do nothing
break ;
case EFI_IMAGE_REL_BASED_HIGH :
// Add second 16 bits of delta
F16 = ( UINT16 * ) data ;
* F16 = ( UINT16 ) ( * F16 + ( UINT16 ) ( ( ( UINT32 ) delta ) > > 16 ) ) ;
break ;
case EFI_IMAGE_REL_BASED_LOW :
// Add first 16 bits of delta
F16 = ( UINT16 * ) data ;
* F16 = ( UINT16 ) ( * F16 + ( UINT16 ) delta ) ;
break ;
case EFI_IMAGE_REL_BASED_HIGHLOW :
// Add first 32 bits of delta
F32 = ( UINT32 * ) data ;
* F32 = * F32 + ( UINT32 ) delta ;
break ;
case EFI_IMAGE_REL_BASED_DIR64 :
// Add all 64 bits of delta
F64 = ( UINT64 * ) data ;
* F64 = * F64 + ( UINT64 ) delta ;
break ;
default :
return ERR_UNKNOWN_RELOCATION_TYPE ;
}
// Next relocation record
Reloc + = 1 ;
}
// Next relocation block
RelocBase = ( EFI_IMAGE_BASE_RELOCATION * ) RelocEnd ;
}
executable = file ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : patchVtf ( QByteArray & vtf )
{
if ( ! oldPeiCoreEntryPoint ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " patchVtf: PEI Core entry point can't be determined. VTF can't be patched. " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_PEI_CORE_ENTRY_POINT_NOT_FOUND ;
}
if ( ! newPeiCoreEntryPoint | | oldPeiCoreEntryPoint = = newPeiCoreEntryPoint )
// No need to patch anything
return ERR_SUCCESS ;
// Replace last occurrence of oldPeiCoreEntryPoint with newPeiCoreEntryPoint
QByteArray old ( ( char * ) & oldPeiCoreEntryPoint , sizeof ( oldPeiCoreEntryPoint ) ) ;
int i = vtf . lastIndexOf ( old ) ;
if ( i = = - 1 ) {
2015-02-06 16:47:19 +08:00
msg ( tr ( " patchVtf: PEI Core entry point can't be found in VTF. VTF not patched. " ) ) ;
2014-05-03 19:21:03 +08:00
return ERR_SUCCESS ;
}
UINT32 * data = ( UINT32 * ) ( vtf . data ( ) + i ) ;
* data = newPeiCoreEntryPoint ;
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : getEntryPoint ( const QByteArray & file , UINT32 & entryPoint )
{
if ( file . isEmpty ( ) )
return ERR_INVALID_FILE ;
// Populate DOS header
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_DOS_HEADER * dosHeader = ( const EFI_IMAGE_DOS_HEADER * ) file . constData ( ) ;
2014-05-03 19:21:03 +08:00
// Check signature
if ( dosHeader - > e_magic = = EFI_IMAGE_DOS_SIGNATURE ) {
UINT32 offset = dosHeader - > e_lfanew ;
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_PE_HEADER * peHeader = ( const EFI_IMAGE_PE_HEADER * ) ( file . constData ( ) + offset ) ;
2014-05-03 19:21:03 +08:00
if ( peHeader - > Signature ! = EFI_IMAGE_PE_SIGNATURE )
return ERR_UNKNOWN_IMAGE_TYPE ;
offset + = sizeof ( EFI_IMAGE_PE_HEADER ) ;
// Skip file header
offset + = sizeof ( EFI_IMAGE_FILE_HEADER ) ;
// Check optional header magic
2015-01-31 22:00:00 +08:00
const UINT16 magic = * ( const UINT16 * ) ( file . constData ( ) + offset ) ;
2014-05-03 19:21:03 +08:00
if ( magic = = EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC ) {
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_OPTIONAL_HEADER32 * optHeader = ( const EFI_IMAGE_OPTIONAL_HEADER32 * ) ( file . constData ( ) + offset ) ;
2014-05-03 19:21:03 +08:00
entryPoint = optHeader - > ImageBase + optHeader - > AddressOfEntryPoint ;
}
else if ( magic = = EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC ) {
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_OPTIONAL_HEADER64 * optHeader = ( const EFI_IMAGE_OPTIONAL_HEADER64 * ) ( file . constData ( ) + offset ) ;
2014-05-03 19:21:03 +08:00
entryPoint = optHeader - > ImageBase + optHeader - > AddressOfEntryPoint ;
}
else
return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE ;
}
else if ( dosHeader - > e_magic = = EFI_IMAGE_TE_SIGNATURE ) {
// Populate TE header
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_TE_HEADER * teHeader = ( const EFI_IMAGE_TE_HEADER * ) file . constData ( ) ;
2014-05-03 19:21:03 +08:00
UINT32 teFixup = teHeader - > StrippedSize - sizeof ( EFI_IMAGE_TE_HEADER ) ;
entryPoint = teHeader - > ImageBase + teHeader - > AddressOfEntryPoint - teFixup ;
}
return ERR_SUCCESS ;
}
UINT8 FfsEngine : : getBase ( const QByteArray & file , UINT32 & base )
{
if ( file . isEmpty ( ) )
return ERR_INVALID_FILE ;
// Populate DOS header
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_DOS_HEADER * dosHeader = ( const EFI_IMAGE_DOS_HEADER * ) file . constData ( ) ;
2014-05-03 19:21:03 +08:00
// Check signature
if ( dosHeader - > e_magic = = EFI_IMAGE_DOS_SIGNATURE ) {
UINT32 offset = dosHeader - > e_lfanew ;
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_PE_HEADER * peHeader = ( const EFI_IMAGE_PE_HEADER * ) ( file . constData ( ) + offset ) ;
2014-05-03 19:21:03 +08:00
if ( peHeader - > Signature ! = EFI_IMAGE_PE_SIGNATURE )
return ERR_UNKNOWN_IMAGE_TYPE ;
offset + = sizeof ( EFI_IMAGE_PE_HEADER ) ;
// Skip file header
offset + = sizeof ( EFI_IMAGE_FILE_HEADER ) ;
// Check optional header magic
2015-01-31 22:00:00 +08:00
const UINT16 magic = * ( const UINT16 * ) ( file . constData ( ) + offset ) ;
2014-05-03 19:21:03 +08:00
if ( magic = = EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC ) {
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_OPTIONAL_HEADER32 * optHeader = ( const EFI_IMAGE_OPTIONAL_HEADER32 * ) ( file . constData ( ) + offset ) ;
2014-05-03 19:21:03 +08:00
base = optHeader - > ImageBase ;
}
else if ( magic = = EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC ) {
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_OPTIONAL_HEADER64 * optHeader = ( const EFI_IMAGE_OPTIONAL_HEADER64 * ) ( file . constData ( ) + offset ) ;
2014-05-03 19:21:03 +08:00
base = optHeader - > ImageBase ;
}
else
return ERR_UNKNOWN_PE_OPTIONAL_HEADER_TYPE ;
}
else if ( dosHeader - > e_magic = = EFI_IMAGE_TE_SIGNATURE ) {
// Populate TE header
2015-01-31 22:00:00 +08:00
const EFI_IMAGE_TE_HEADER * teHeader = ( const EFI_IMAGE_TE_HEADER * ) file . constData ( ) ;
//!TODO: add handling
base = teHeader - > ImageBase ;
2014-05-03 19:21:03 +08:00
}
return ERR_SUCCESS ;
}
UINT32 FfsEngine : : crc32 ( UINT32 initial , const UINT8 * buffer , UINT32 length )
{
static const UINT32 crcTable [ 256 ] = {
0x00000000 , 0x77073096 , 0xEE0E612C , 0x990951BA , 0x076DC419 , 0x706AF48F , 0xE963A535 ,
0x9E6495A3 , 0x0EDB8832 , 0x79DCB8A4 , 0xE0D5E91E , 0x97D2D988 , 0x09B64C2B , 0x7EB17CBD ,
0xE7B82D07 , 0x90BF1D91 , 0x1DB71064 , 0x6AB020F2 , 0xF3B97148 , 0x84BE41DE , 0x1ADAD47D ,
0x6DDDE4EB , 0xF4D4B551 , 0x83D385C7 , 0x136C9856 , 0x646BA8C0 , 0xFD62F97A , 0x8A65C9EC ,
0x14015C4F , 0x63066CD9 , 0xFA0F3D63 , 0x8D080DF5 , 0x3B6E20C8 , 0x4C69105E , 0xD56041E4 ,
0xA2677172 , 0x3C03E4D1 , 0x4B04D447 , 0xD20D85FD , 0xA50AB56B , 0x35B5A8FA , 0x42B2986C ,
0xDBBBC9D6 , 0xACBCF940 , 0x32D86CE3 , 0x45DF5C75 , 0xDCD60DCF , 0xABD13D59 , 0x26D930AC ,
0x51DE003A , 0xC8D75180 , 0xBFD06116 , 0x21B4F4B5 , 0x56B3C423 , 0xCFBA9599 , 0xB8BDA50F ,
0x2802B89E , 0x5F058808 , 0xC60CD9B2 , 0xB10BE924 , 0x2F6F7C87 , 0x58684C11 , 0xC1611DAB ,
0xB6662D3D , 0x76DC4190 , 0x01DB7106 , 0x98D220BC , 0xEFD5102A , 0x71B18589 , 0x06B6B51F ,
0x9FBFE4A5 , 0xE8B8D433 , 0x7807C9A2 , 0x0F00F934 , 0x9609A88E , 0xE10E9818 , 0x7F6A0DBB ,
0x086D3D2D , 0x91646C97 , 0xE6635C01 , 0x6B6B51F4 , 0x1C6C6162 , 0x856530D8 , 0xF262004E ,
0x6C0695ED , 0x1B01A57B , 0x8208F4C1 , 0xF50FC457 , 0x65B0D9C6 , 0x12B7E950 , 0x8BBEB8EA ,
0xFCB9887C , 0x62DD1DDF , 0x15DA2D49 , 0x8CD37CF3 , 0xFBD44C65 , 0x4DB26158 , 0x3AB551CE ,
0xA3BC0074 , 0xD4BB30E2 , 0x4ADFA541 , 0x3DD895D7 , 0xA4D1C46D , 0xD3D6F4FB , 0x4369E96A ,
0x346ED9FC , 0xAD678846 , 0xDA60B8D0 , 0x44042D73 , 0x33031DE5 , 0xAA0A4C5F , 0xDD0D7CC9 ,
0x5005713C , 0x270241AA , 0xBE0B1010 , 0xC90C2086 , 0x5768B525 , 0x206F85B3 , 0xB966D409 ,
0xCE61E49F , 0x5EDEF90E , 0x29D9C998 , 0xB0D09822 , 0xC7D7A8B4 , 0x59B33D17 , 0x2EB40D81 ,
0xB7BD5C3B , 0xC0BA6CAD , 0xEDB88320 , 0x9ABFB3B6 , 0x03B6E20C , 0x74B1D29A , 0xEAD54739 ,
0x9DD277AF , 0x04DB2615 , 0x73DC1683 , 0xE3630B12 , 0x94643B84 , 0x0D6D6A3E , 0x7A6A5AA8 ,
0xE40ECF0B , 0x9309FF9D , 0x0A00AE27 , 0x7D079EB1 , 0xF00F9344 , 0x8708A3D2 , 0x1E01F268 ,
0x6906C2FE , 0xF762575D , 0x806567CB , 0x196C3671 , 0x6E6B06E7 , 0xFED41B76 , 0x89D32BE0 ,
0x10DA7A5A , 0x67DD4ACC , 0xF9B9DF6F , 0x8EBEEFF9 , 0x17B7BE43 , 0x60B08ED5 , 0xD6D6A3E8 ,
0xA1D1937E , 0x38D8C2C4 , 0x4FDFF252 , 0xD1BB67F1 , 0xA6BC5767 , 0x3FB506DD , 0x48B2364B ,
0xD80D2BDA , 0xAF0A1B4C , 0x36034AF6 , 0x41047A60 , 0xDF60EFC3 , 0xA867DF55 , 0x316E8EEF ,
0x4669BE79 , 0xCB61B38C , 0xBC66831A , 0x256FD2A0 , 0x5268E236 , 0xCC0C7795 , 0xBB0B4703 ,
0x220216B9 , 0x5505262F , 0xC5BA3BBE , 0xB2BD0B28 , 0x2BB45A92 , 0x5CB36A04 , 0xC2D7FFA7 ,
0xB5D0CF31 , 0x2CD99E8B , 0x5BDEAE1D , 0x9B64C2B0 , 0xEC63F226 , 0x756AA39C , 0x026D930A ,
0x9C0906A9 , 0xEB0E363F , 0x72076785 , 0x05005713 , 0x95BF4A82 , 0xE2B87A14 , 0x7BB12BAE ,
0x0CB61B38 , 0x92D28E9B , 0xE5D5BE0D , 0x7CDCEFB7 , 0x0BDBDF21 , 0x86D3D2D4 , 0xF1D4E242 ,
0x68DDB3F8 , 0x1FDA836E , 0x81BE16CD , 0xF6B9265B , 0x6FB077E1 , 0x18B74777 , 0x88085AE6 ,
0xFF0F6A70 , 0x66063BCA , 0x11010B5C , 0x8F659EFF , 0xF862AE69 , 0x616BFFD3 , 0x166CCF45 ,
0xA00AE278 , 0xD70DD2EE , 0x4E048354 , 0x3903B3C2 , 0xA7672661 , 0xD06016F7 , 0x4969474D ,
0x3E6E77DB , 0xAED16A4A , 0xD9D65ADC , 0x40DF0B66 , 0x37D83BF0 , 0xA9BCAE53 , 0xDEBB9EC5 ,
0x47B2CF7F , 0x30B5FFE9 , 0xBDBDF21C , 0xCABAC28A , 0x53B39330 , 0x24B4A3A6 , 0xBAD03605 ,
0xCDD70693 , 0x54DE5729 , 0x23D967BF , 0xB3667A2E , 0xC4614AB8 , 0x5D681B02 , 0x2A6F2B94 ,
0xB40BBE37 , 0xC30C8EA1 , 0x5A05DF1B , 0x2D02EF8D } ;
UINT32 crc32 ;
UINT32 i ;
// Accumulate crc32 for buffer
crc32 = initial ^ 0xFFFFFFFF ;
for ( i = 0 ; i < length ; i + + ) {
crc32 = ( crc32 > > 8 ) ^ crcTable [ ( crc32 ^ buffer [ i ] ) & 0xFF ] ;
}
return ( crc32 ^ 0xFFFFFFFF ) ;
}
2014-08-15 19:24:03 +08:00
UINT8 FfsEngine : : dump ( const QModelIndex & index , const QString & path , const QString & guid )
2014-08-16 21:54:42 +08:00
{
2014-11-18 23:01:20 +08:00
dumped = false ;
UINT8 result = recursiveDump ( index , path , guid ) ;
if ( result )
return result ;
else if ( ! dumped )
return ERR_ITEM_NOT_FOUND ;
return ERR_SUCCESS ;
2014-08-16 21:54:42 +08:00
}
UINT8 FfsEngine : : recursiveDump ( const QModelIndex & index , const QString & path , const QString & guid )
2014-05-03 19:21:03 +08:00
{
if ( ! index . isValid ( ) )
return ERR_INVALID_PARAMETER ;
2014-07-25 07:59:51 +08:00
2014-05-03 19:21:03 +08:00
QDir dir ;
2014-11-18 23:01:20 +08:00
if ( guid . isEmpty ( ) | |
2015-01-31 22:00:00 +08:00
guidToQString ( * ( const EFI_GUID * ) model - > header ( index ) . constData ( ) ) = = guid | |
guidToQString ( * ( const EFI_GUID * ) model - > header ( model - > findParentOfType ( index , Types : : File ) ) . constData ( ) ) = = guid ) {
2014-11-18 23:01:20 +08:00
if ( dir . cd ( path ) )
return ERR_DIR_ALREADY_EXIST ;
if ( ! dir . mkpath ( path ) )
return ERR_DIR_CREATE ;
QFile file ;
if ( ! model - > header ( index ) . isEmpty ( ) ) {
file . setFileName ( tr ( " %1/header.bin " ) . arg ( path ) ) ;
if ( ! file . open ( QFile : : WriteOnly ) )
return ERR_FILE_OPEN ;
file . write ( model - > header ( index ) ) ;
file . close ( ) ;
}
if ( ! model - > body ( index ) . isEmpty ( ) ) {
file . setFileName ( tr ( " %1/body.bin " ) . arg ( path ) ) ;
if ( ! file . open ( QFile : : WriteOnly ) )
return ERR_FILE_OPEN ;
file . write ( model - > body ( index ) ) ;
file . close ( ) ;
}
QString info = tr ( " Type: %1 \n Subtype: %2 \n %3%4 " )
2015-01-31 22:00:00 +08:00
. arg ( itemTypeToQString ( model - > type ( index ) ) )
2015-02-06 16:47:19 +08:00
. arg ( itemSubtypeToQString ( model - > type ( index ) , model - > subtype ( index ) ) )
2015-01-31 22:00:00 +08:00
. arg ( model - > text ( index ) . isEmpty ( ) ? " " : tr ( " Text: %1 \n " ) . arg ( model - > text ( index ) ) )
2014-11-18 23:01:20 +08:00
. arg ( model - > info ( index ) ) ;
file . setFileName ( tr ( " %1/info.txt " ) . arg ( path ) ) ;
if ( ! file . open ( QFile : : Text | QFile : : WriteOnly ) )
return ERR_FILE_OPEN ;
file . write ( info . toLatin1 ( ) ) ;
file . close ( ) ;
dumped = true ;
}
2014-05-03 19:21:03 +08:00
UINT8 result ;
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
QModelIndex childIndex = index . child ( i , 0 ) ;
2015-01-31 22:00:00 +08:00
QString childPath = QString ( " %1/%2 %3 " ) . arg ( path ) . arg ( i ) . arg ( model - > text ( childIndex ) . isEmpty ( ) ? model - > name ( childIndex ) : model - > text ( childIndex ) ) ;
2014-08-16 21:54:42 +08:00
result = recursiveDump ( childIndex , childPath , guid ) ;
2014-05-03 19:21:03 +08:00
if ( result )
return result ;
}
return ERR_SUCCESS ;
2014-05-03 22:53:27 +08:00
}
2014-07-05 20:56:56 +08:00
UINT8 FfsEngine : : patch ( const QModelIndex & index , const QVector < PatchData > & patches )
2014-06-19 11:45:20 +08:00
{
2014-07-05 20:56:56 +08:00
if ( ! index . isValid ( ) | | patches . isEmpty ( ) | | model - > rowCount ( index ) )
2014-06-19 11:45:20 +08:00
return ERR_INVALID_PARAMETER ;
2014-07-05 20:56:56 +08:00
// Skip removed items
2014-06-19 11:45:20 +08:00
if ( model - > action ( index ) = = Actions : : Remove )
2014-07-05 20:56:56 +08:00
return ERR_NOTHING_TO_PATCH ;
UINT8 result ;
2014-07-25 07:59:51 +08:00
2014-07-05 20:56:56 +08:00
// Apply patches to item's body
QByteArray body = model - > body ( index ) ;
PatchData current ;
Q_FOREACH ( current , patches )
{
if ( current . type = = PATCH_TYPE_OFFSET ) {
result = patchViaOffset ( body , current . offset , current . hexReplacePattern ) ;
if ( result )
return result ;
}
else if ( current . type = = PATCH_TYPE_PATTERN ) {
result = patchViaPattern ( body , current . hexFindPattern , current . hexReplacePattern ) ;
if ( result )
return result ;
}
2014-07-25 07:59:51 +08:00
else
2014-07-05 20:56:56 +08:00
return ERR_UNKNOWN_PATCH_TYPE ;
}
2014-06-19 11:45:20 +08:00
2014-07-05 20:56:56 +08:00
if ( body ! = model - > body ( index ) ) {
2014-06-19 11:45:20 +08:00
QByteArray patched = model - > header ( index ) ;
2014-07-05 20:56:56 +08:00
patched . append ( body ) ;
2014-06-19 11:45:20 +08:00
return replace ( index , patched , REPLACE_MODE_AS_IS ) ;
}
2014-07-25 07:59:51 +08:00
2014-07-05 20:56:56 +08:00
return ERR_NOTHING_TO_PATCH ;
}
UINT8 FfsEngine : : patchViaOffset ( QByteArray & data , const UINT32 offset , const QByteArray & hexReplacePattern )
{
QByteArray body = data ;
2014-07-25 07:59:51 +08:00
2014-07-05 20:56:56 +08:00
// Skip patterns with odd length
2014-07-25 07:59:51 +08:00
if ( hexReplacePattern . length ( ) % 2 > 0 )
2014-07-05 20:56:56 +08:00
return ERR_INVALID_PARAMETER ;
2014-07-25 07:59:51 +08:00
2014-07-05 20:56:56 +08:00
// Check offset bounds
2014-07-12 18:27:42 +08:00
if ( offset > ( UINT32 ) ( body . length ( ) - hexReplacePattern . length ( ) / 2 ) )
2014-07-05 20:56:56 +08:00
return ERR_PATCH_OFFSET_OUT_OF_BOUNDS ;
// Parse replace pattern
QByteArray replacePattern ;
bool converted ;
for ( int i = 0 ; i < hexReplacePattern . length ( ) / 2 ; i + + ) {
QByteArray hex = hexReplacePattern . mid ( 2 * i , 2 ) ;
UINT8 value = 0 ;
2014-07-25 07:59:51 +08:00
if ( ! hex . contains ( ' . ' ) ) { // Normal byte pattern
2014-07-05 20:56:56 +08:00
value = ( UINT8 ) hex . toUShort ( & converted , 16 ) ;
if ( ! converted )
return ERR_INVALID_SYMBOL ;
}
else { // Placeholder byte pattern
if ( hex [ 0 ] = = ' . ' & & hex [ 1 ] = = ' . ' ) { // Full byte placeholder
value = body . at ( offset + i ) ;
2014-06-19 11:45:20 +08:00
}
2014-07-05 20:56:56 +08:00
else if ( hex [ 0 ] = = ' . ' ) { // Upper byte part placeholder
hex [ 0 ] = ' 0 ' ;
2014-07-25 07:59:51 +08:00
value = ( UINT8 ) ( body . at ( offset + i ) & 0xF0 ) ;
2014-07-05 20:56:56 +08:00
value + = ( UINT8 ) hex . toUShort ( & converted , 16 ) ;
if ( ! converted )
return ERR_INVALID_SYMBOL ;
}
else if ( hex [ 1 ] = = ' . ' ) { // Lower byte part placeholder
hex [ 1 ] = ' 0 ' ;
value = ( UINT8 ) ( body . at ( offset + i ) & 0x0F ) ;
value + = ( UINT8 ) hex . toUShort ( & converted , 16 ) ;
if ( ! converted )
return ERR_INVALID_SYMBOL ;
}
else
return ERR_INVALID_SYMBOL ;
2014-06-19 11:45:20 +08:00
}
2014-07-05 20:56:56 +08:00
// Append calculated value to real pattern
replacePattern . append ( value ) ;
}
body . replace ( offset , replacePattern . length ( ) , replacePattern ) ;
2015-01-31 22:00:00 +08:00
msg ( tr ( " patch: replaced %1 bytes at offset %2h %3 -> %4 " )
2014-07-05 20:56:56 +08:00
. arg ( replacePattern . length ( ) )
2015-01-31 22:00:00 +08:00
. hexarg ( offset )
2014-11-09 05:24:53 +08:00
. arg ( QString ( data . mid ( offset , replacePattern . length ( ) ) . toHex ( ) ) . toUpper ( ) )
2014-11-09 06:30:32 +08:00
. arg ( QString ( replacePattern . toHex ( ) ) . toUpper ( ) ) ) ;
2014-07-05 20:56:56 +08:00
data = body ;
return ERR_SUCCESS ;
}
2014-07-14 06:38:34 +08:00
UINT8 FfsEngine : : patchViaPattern ( QByteArray & data , const QByteArray & hexFindPattern , const QByteArray & hexReplacePattern )
2014-07-05 20:56:56 +08:00
{
QByteArray body = data ;
// Skip patterns with odd length
if ( hexFindPattern . length ( ) % 2 > 0 | | hexReplacePattern . length ( ) % 2 > 0 )
return ERR_INVALID_PARAMETER ;
// Convert file body to hex;
QString hexBody = QString ( body . toHex ( ) ) ;
QRegExp regexp = QRegExp ( QString ( hexFindPattern ) , Qt : : CaseInsensitive ) ;
2014-07-14 06:38:34 +08:00
INT32 offset = regexp . indexIn ( hexBody ) ;
2014-07-05 20:56:56 +08:00
while ( offset > = 0 ) {
if ( offset % 2 = = 0 ) {
2014-07-25 07:59:51 +08:00
UINT8 result = patchViaOffset ( body , offset / 2 , hexReplacePattern ) ;
2014-07-05 20:56:56 +08:00
if ( result )
return result ;
2014-06-19 11:45:20 +08:00
}
2014-07-05 20:56:56 +08:00
offset = regexp . indexIn ( hexBody , offset + 1 ) ;
2014-06-19 11:45:20 +08:00
}
2014-07-05 20:56:56 +08:00
data = body ;
2014-06-19 11:45:20 +08:00
return ERR_SUCCESS ;
2014-10-30 12:34:19 +08:00
}
2015-02-13 04:15:11 +08:00