2016-07-09 16:08:32 +08:00
/* ffsparser.cpp
2015-03-13 14:48:53 +08:00
2018-04-30 13:33:19 +08:00
Copyright ( c ) 2018 , Nikolaj Schlej . All rights reserved .
2015-03-13 14:48:53 +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 .
*/
2018-05-08 15:48:04 +08:00
// A workaround for compilers not supporting c++11 and c11
// for using PRIX64.
# define __STDC_FORMAT_MACROS
2016-02-02 09:08:08 +08:00
# include "ffsparser.h"
2016-07-06 00:19:04 +08:00
# include <map>
2016-03-01 15:20:44 +08:00
# include <algorithm>
2018-05-08 08:02:07 +08:00
# include <inttypes.h>
2016-10-10 14:05:04 +08:00
# include "descriptor.h"
# include "ffs.h"
# include "gbe.h"
# include "me.h"
# include "fit.h"
# include "nvram.h"
# include "utility.h"
# include "peimage.h"
# include "parsingdata.h"
# include "types.h"
2018-10-08 17:58:12 +08:00
# include "utility.h"
2015-03-13 14:48:53 +08:00
2017-12-11 09:56:00 +08:00
# include "nvramparser.h"
# include "meparser.h"
# ifndef QT_CORE_LIB
namespace Qt {
enum GlobalColor {
red = 7 ,
2019-08-20 02:36:02 +08:00
green = 8 ,
2017-12-11 09:56:00 +08:00
cyan = 10 ,
yellow = 12 ,
} ;
}
# endif
2017-10-12 13:59:23 +08:00
2019-08-20 02:36:02 +08:00
// Region info
2016-02-02 09:08:08 +08:00
struct REGION_INFO {
UINT32 offset ;
UINT32 length ;
UINT8 type ;
2016-06-26 11:54:21 +08:00
UByteArray data ;
2016-02-02 09:08:08 +08:00
friend bool operator < ( const REGION_INFO & lhs , const REGION_INFO & rhs ) { return lhs . offset < rhs . offset ; }
} ;
2015-03-13 14:48:53 +08:00
2019-08-20 02:36:02 +08:00
// BPDT partition info
struct BPDT_PARTITION_INFO {
BPDT_ENTRY ptEntry ;
UINT8 type ;
UModelIndex index ;
friend bool operator < ( const BPDT_PARTITION_INFO & lhs , const BPDT_PARTITION_INFO & rhs ) { return lhs . ptEntry . Offset < rhs . ptEntry . Offset ; }
} ;
// CPD partition info
struct CPD_PARTITION_INFO {
CPD_ENTRY ptEntry ;
UINT8 type ;
UModelIndex index ;
friend bool operator < ( const CPD_PARTITION_INFO & lhs , const CPD_PARTITION_INFO & rhs ) { return lhs . ptEntry . Offset . Offset < rhs . ptEntry . Offset . Offset ; }
} ;
2017-12-11 09:56:00 +08:00
// Constructor
FfsParser : : FfsParser ( TreeModel * treeModel ) : model ( treeModel ) ,
2018-04-30 13:33:19 +08:00
imageBase ( 0 ) , addressDiff ( 0x100000000ULL ) ,
2018-10-08 17:58:12 +08:00
bgAcmFound ( false ) , bgKeyManifestFound ( false ) , bgBootPolicyFound ( false ) , bgProtectedRegionsBase ( 0 ) {
2017-12-11 09:56:00 +08:00
nvramParser = new NvramParser ( treeModel , this ) ;
2019-08-20 02:36:02 +08:00
meParser = new MeParser ( treeModel , this ) ;
2017-12-11 09:56:00 +08:00
}
// Destructor
FfsParser : : ~ FfsParser ( ) {
delete nvramParser ;
delete meParser ;
}
// Obtain parser messages
std : : vector < std : : pair < UString , UModelIndex > > FfsParser : : getMessages ( ) const {
std : : vector < std : : pair < UString , UModelIndex > > meVector = meParser - > getMessages ( ) ;
std : : vector < std : : pair < UString , UModelIndex > > nvramVector = nvramParser - > getMessages ( ) ;
std : : vector < std : : pair < UString , UModelIndex > > resultVector = messagesVector ;
resultVector . insert ( resultVector . end ( ) , meVector . begin ( ) , meVector . end ( ) ) ;
resultVector . insert ( resultVector . end ( ) , nvramVector . begin ( ) , nvramVector . end ( ) ) ;
return resultVector ;
}
2016-02-02 09:08:08 +08:00
// Firmware image parsing functions
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parse ( const UByteArray & buffer )
2015-03-13 14:48:53 +08:00
{
2016-06-26 11:54:21 +08:00
UModelIndex root ;
2017-02-14 14:39:16 +08:00
2018-10-08 17:58:12 +08:00
// Reset global parser state
2017-10-12 13:59:23 +08:00
openedImage = buffer ;
2018-10-08 17:58:12 +08:00
imageBase = 0 ;
2019-01-07 21:05:57 +08:00
addressDiff = 0x100000000ULL ;
2018-10-08 17:58:12 +08:00
bgAcmFound = false ;
bgKeyManifestFound = false ;
bgBootPolicyFound = false ;
bgProtectedRegionsBase = 0 ;
lastVtf = UModelIndex ( ) ;
fitTable . clear ( ) ;
securityInfo = " " ;
bgAcmFound = false ;
bgKeyManifestFound = false ;
bgBootPolicyFound = false ;
bgKmHash = UByteArray ( ) ;
bgBpHash = UByteArray ( ) ;
bgBpDigest = UByteArray ( ) ;
bgProtectedRanges . clear ( ) ;
bgDxeCoreIndex = UModelIndex ( ) ;
// Parse input buffer
2016-06-26 11:54:21 +08:00
USTATUS result = performFirstPass ( buffer , root ) ;
2019-01-07 21:05:57 +08:00
if ( result = = U_SUCCESS ) {
if ( lastVtf . isValid ( ) ) {
result = performSecondPass ( root ) ;
}
else {
msg ( usprintf ( " %s: not a single Volume Top File is found, the image may be corrupted " , __FUNCTION__ ) ) ;
}
2018-04-30 13:33:19 +08:00
}
2016-02-02 09:08:08 +08:00
2019-01-07 21:05:57 +08:00
addInfoRecursive ( root ) ;
2016-02-02 09:08:08 +08:00
return result ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : performFirstPass ( const UByteArray & buffer , UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
2019-07-25 01:30:59 +08:00
// Sanity check
2018-04-30 13:33:19 +08:00
if ( buffer . isEmpty ( ) ) {
return EFI_INVALID_PARAMETER ;
}
2015-09-13 23:32:22 +08:00
2018-10-08 17:58:12 +08:00
USTATUS result ;
2018-04-30 13:33:19 +08:00
// Try parsing as UEFI Capsule
2018-10-08 17:58:12 +08:00
result = parseCapsule ( buffer , 0 , UModelIndex ( ) , index ) ; ;
2018-04-30 13:33:19 +08:00
if ( result ! = U_ITEM_NOT_FOUND ) {
return result ;
}
// Try parsing as Intel image
result = parseIntelImage ( buffer , 0 , UModelIndex ( ) , index ) ;
if ( result ! = U_ITEM_NOT_FOUND ) {
return result ;
}
// Parse as generic image
return parseGenericImage ( buffer , 0 , UModelIndex ( ) , index ) ;
}
USTATUS FfsParser : : parseGenericImage ( const UByteArray & buffer , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
{
// Parse as generic UEFI image
UString name ( " UEFI image " ) ;
UString info = usprintf ( " Full size: %Xh (%u) " , buffer . size ( ) , buffer . size ( ) ) ;
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Image , Subtypes : : UefiImage , name , UString ( ) , info , UByteArray ( ) , buffer , UByteArray ( ) , Fixed , parent ) ;
2018-04-30 13:33:19 +08:00
// Parse the image as raw area
2019-01-07 21:05:57 +08:00
bgProtectedRegionsBase = imageBase = model - > base ( parent ) + localOffset ;
2018-04-30 13:33:19 +08:00
return parseRawArea ( index ) ;
}
2018-10-08 17:58:12 +08:00
USTATUS FfsParser : : parseCapsule ( const UByteArray & capsule , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2018-04-30 13:33:19 +08:00
{
2015-12-12 17:59:38 +08:00
// Check buffer size to be more than or equal to size of EFI_CAPSULE_HEADER
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) capsule . size ( ) < sizeof ( EFI_CAPSULE_HEADER ) ) {
return U_ITEM_NOT_FOUND ;
2015-03-13 14:48:53 +08:00
}
2015-12-12 17:59:38 +08:00
UINT32 capsuleHeaderSize = 0 ;
// Check buffer for being normal EFI capsule header
2018-04-30 13:33:19 +08:00
if ( capsule . startsWith ( EFI_CAPSULE_GUID )
2019-01-20 18:23:28 +08:00
| | capsule . startsWith ( EFI_FMP_CAPSULE_GUID )
2018-04-30 13:33:19 +08:00
| | capsule . startsWith ( INTEL_CAPSULE_GUID )
| | capsule . startsWith ( LENOVO_CAPSULE_GUID )
| | capsule . startsWith ( LENOVO2_CAPSULE_GUID ) ) {
2015-03-13 14:48:53 +08:00
// Get info
2018-04-30 13:33:19 +08:00
const EFI_CAPSULE_HEADER * capsuleHeader = ( const EFI_CAPSULE_HEADER * ) capsule . constData ( ) ;
2015-12-12 17:59:38 +08:00
// Check sanity of HeaderSize and CapsuleImageSize values
2018-04-30 13:33:19 +08:00
if ( capsuleHeader - > HeaderSize = = 0 | | capsuleHeader - > HeaderSize > ( UINT32 ) capsule . size ( )
| | capsuleHeader - > HeaderSize > capsuleHeader - > CapsuleImageSize ) {
msg ( usprintf ( " %s: UEFI capsule header size of %Xh (%u) bytes is invalid " , __FUNCTION__ ,
capsuleHeader - > HeaderSize ,
capsuleHeader - > HeaderSize ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_CAPSULE ;
2015-12-12 17:59:38 +08:00
}
2018-10-08 17:58:12 +08:00
if ( capsuleHeader - > CapsuleImageSize > ( UINT32 ) capsule . size ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: UEFI capsule image size of %Xh (%u) bytes is invalid " , __FUNCTION__ ,
capsuleHeader - > CapsuleImageSize ,
capsuleHeader - > CapsuleImageSize ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_CAPSULE ;
2015-12-12 17:59:38 +08:00
}
2015-03-13 14:48:53 +08:00
capsuleHeaderSize = capsuleHeader - > HeaderSize ;
2018-04-30 13:33:19 +08:00
UByteArray header = capsule . left ( capsuleHeaderSize ) ;
UByteArray body = capsule . mid ( capsuleHeaderSize ) ;
2016-06-26 11:54:21 +08:00
UString name ( " UEFI capsule " ) ;
2018-04-30 13:33:19 +08:00
UString info = UString ( " Capsule GUID: " ) + guidToUString ( capsuleHeader - > CapsuleGuid , false ) +
usprintf ( " \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Image size: %Xh (%u) \n Flags: %08Xh " ,
capsule . size ( ) , capsule . size ( ) ,
capsuleHeaderSize , capsuleHeaderSize ,
capsuleHeader - > CapsuleImageSize - capsuleHeaderSize , capsuleHeader - > CapsuleImageSize - capsuleHeaderSize ,
capsuleHeader - > Flags ) ;
2015-09-13 23:32:22 +08:00
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Capsule , Subtypes : : UefiCapsule , name , UString ( ) , info , header , body , UByteArray ( ) , Fixed , parent ) ;
2015-03-13 14:48:53 +08:00
}
2015-09-01 03:34:42 +08:00
// Check buffer for being Toshiba capsule header
2018-04-30 13:33:19 +08:00
else if ( capsule . startsWith ( TOSHIBA_CAPSULE_GUID ) ) {
2015-09-01 03:34:42 +08:00
// Get info
2018-04-30 13:33:19 +08:00
const TOSHIBA_CAPSULE_HEADER * capsuleHeader = ( const TOSHIBA_CAPSULE_HEADER * ) capsule . constData ( ) ;
2015-12-12 17:59:38 +08:00
// Check sanity of HeaderSize and FullSize values
2018-04-30 13:33:19 +08:00
if ( capsuleHeader - > HeaderSize = = 0 | | capsuleHeader - > HeaderSize > ( UINT32 ) capsule . size ( )
| | capsuleHeader - > HeaderSize > capsuleHeader - > FullSize ) {
msg ( usprintf ( " %s: Toshiba capsule header size of %Xh (%u) bytes is invalid " , __FUNCTION__ ,
capsuleHeader - > HeaderSize , capsuleHeader - > HeaderSize ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_CAPSULE ;
2015-12-12 17:59:38 +08:00
}
2018-10-08 17:58:12 +08:00
if ( capsuleHeader - > FullSize > ( UINT32 ) capsule . size ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: Toshiba capsule full size of %Xh (%u) bytes is invalid " , __FUNCTION__ ,
capsuleHeader - > FullSize , capsuleHeader - > FullSize ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_CAPSULE ;
2015-12-12 17:59:38 +08:00
}
2015-09-01 03:34:42 +08:00
capsuleHeaderSize = capsuleHeader - > HeaderSize ;
2018-04-30 13:33:19 +08:00
UByteArray header = capsule . left ( capsuleHeaderSize ) ;
UByteArray body = capsule . mid ( capsuleHeaderSize ) ;
2016-06-26 11:54:21 +08:00
UString name ( " Toshiba capsule " ) ;
2018-04-30 13:33:19 +08:00
UString info = UString ( " Capsule GUID: " ) + guidToUString ( capsuleHeader - > CapsuleGuid , false ) +
usprintf ( " \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Image size: %Xh (%u) \n Flags: %08Xh " ,
capsule . size ( ) , capsule . size ( ) ,
capsuleHeaderSize , capsuleHeaderSize ,
capsuleHeader - > FullSize - capsuleHeaderSize , capsuleHeader - > FullSize - capsuleHeaderSize ,
capsuleHeader - > Flags ) ;
2015-09-13 23:32:22 +08:00
2015-09-01 03:34:42 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Capsule , Subtypes : : ToshibaCapsule , name , UString ( ) , info , header , body , UByteArray ( ) , Fixed , parent ) ;
2015-09-01 03:34:42 +08:00
}
2016-02-02 09:08:08 +08:00
// Check buffer for being extended Aptio capsule header
2018-04-30 13:33:19 +08:00
else if ( capsule . startsWith ( APTIO_SIGNED_CAPSULE_GUID )
| | capsule . startsWith ( APTIO_UNSIGNED_CAPSULE_GUID ) ) {
bool signedCapsule = capsule . startsWith ( APTIO_SIGNED_CAPSULE_GUID ) ;
2015-12-12 17:59:38 +08:00
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) capsule . size ( ) < = sizeof ( APTIO_CAPSULE_HEADER ) ) {
msg ( usprintf ( " %s: AMI capsule image file is smaller than minimum size of 20h (32) bytes " , __FUNCTION__ ) ) ;
return U_INVALID_CAPSULE ;
2015-12-12 17:59:38 +08:00
}
2015-03-13 14:48:53 +08:00
// Get info
2018-04-30 13:33:19 +08:00
const APTIO_CAPSULE_HEADER * capsuleHeader = ( const APTIO_CAPSULE_HEADER * ) capsule . constData ( ) ;
2015-12-12 17:59:38 +08:00
// Check sanity of RomImageOffset and CapsuleImageSize values
2018-04-30 13:33:19 +08:00
if ( capsuleHeader - > RomImageOffset = = 0 | | capsuleHeader - > RomImageOffset > ( UINT32 ) capsule . size ( )
| | capsuleHeader - > RomImageOffset > capsuleHeader - > CapsuleHeader . CapsuleImageSize ) {
msg ( usprintf ( " %s: AMI capsule image offset of %Xh (%u) bytes is invalid " , __FUNCTION__ ,
capsuleHeader - > RomImageOffset , capsuleHeader - > RomImageOffset ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_CAPSULE ;
2015-12-12 17:59:38 +08:00
}
2018-10-08 17:58:12 +08:00
if ( capsuleHeader - > CapsuleHeader . CapsuleImageSize > ( UINT32 ) capsule . size ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: AMI capsule image size of %Xh (%u) bytes is invalid " , __FUNCTION__ ,
capsuleHeader - > CapsuleHeader . CapsuleImageSize ,
capsuleHeader - > CapsuleHeader . CapsuleImageSize ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_CAPSULE ;
2015-12-12 17:59:38 +08:00
}
2015-03-13 14:48:53 +08:00
capsuleHeaderSize = capsuleHeader - > RomImageOffset ;
2018-04-30 13:33:19 +08:00
UByteArray header = capsule . left ( capsuleHeaderSize ) ;
UByteArray body = capsule . mid ( capsuleHeaderSize ) ;
2016-06-26 11:54:21 +08:00
UString name ( " AMI Aptio capsule " ) ;
2017-02-14 14:39:16 +08:00
UString info = UString ( " Capsule GUID: " ) + guidToUString ( capsuleHeader - > CapsuleHeader . CapsuleGuid , false ) +
2018-04-30 13:33:19 +08:00
usprintf ( " \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Image size: %Xh (%u) \n Flags: %08Xh " ,
capsule . size ( ) , capsule . size ( ) ,
capsuleHeaderSize , capsuleHeaderSize ,
capsuleHeader - > CapsuleHeader . CapsuleImageSize - capsuleHeaderSize , capsuleHeader - > CapsuleHeader . CapsuleImageSize - capsuleHeaderSize ,
capsuleHeader - > CapsuleHeader . Flags ) ;
2015-09-13 23:32:22 +08:00
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Capsule , signedCapsule ? Subtypes : : AptioSignedCapsule : Subtypes : : AptioUnsignedCapsule , name , UString ( ) , info , header , body , UByteArray ( ) , Fixed , parent ) ;
2015-03-13 14:48:53 +08:00
// Show message about possible Aptio signature break
if ( signedCapsule ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: Aptio capsule signature may become invalid after image modifications " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
}
}
2018-04-30 13:33:19 +08:00
// Capsule present
if ( capsuleHeaderSize > 0 ) {
UByteArray image = capsule . mid ( capsuleHeaderSize ) ;
2016-06-26 11:54:21 +08:00
UModelIndex imageIndex ;
2018-04-30 13:33:19 +08:00
// Try parsing as Intel image
USTATUS result = parseIntelImage ( image , capsuleHeaderSize , index , imageIndex ) ;
if ( result ! = U_ITEM_NOT_FOUND ) {
2015-03-13 14:48:53 +08:00
return result ;
2016-02-02 09:08:08 +08:00
}
2015-03-13 14:48:53 +08:00
2018-04-30 13:33:19 +08:00
// Parse as generic image
return parseGenericImage ( image , capsuleHeaderSize , index , imageIndex ) ;
}
2015-04-02 16:04:37 +08:00
2018-04-30 13:33:19 +08:00
return U_ITEM_NOT_FOUND ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseIntelImage ( const UByteArray & intelImage , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
2018-04-30 13:33:19 +08:00
// Check for buffer size to be greater or equal to descriptor region size
if ( intelImage . size ( ) < FLASH_DESCRIPTOR_SIZE ) {
msg ( usprintf ( " %s: input file is smaller than minimum descriptor size of %Xh (%u) bytes " , __FUNCTION__ , FLASH_DESCRIPTOR_SIZE , FLASH_DESCRIPTOR_SIZE ) ) ;
return U_ITEM_NOT_FOUND ;
}
2015-03-13 14:48:53 +08:00
// Store the beginning of descriptor as descriptor base address
2018-04-30 13:33:19 +08:00
const FLASH_DESCRIPTOR_HEADER * descriptor = ( const FLASH_DESCRIPTOR_HEADER * ) intelImage . constData ( ) ;
2015-03-13 14:48:53 +08:00
2018-04-30 13:33:19 +08:00
// Check descriptor signature
if ( descriptor - > Signature ! = FLASH_DESCRIPTOR_SIGNATURE ) {
return U_ITEM_NOT_FOUND ;
2015-03-13 14:48:53 +08:00
}
// Parse descriptor map
2018-04-30 13:33:19 +08:00
const FLASH_DESCRIPTOR_MAP * descriptorMap = ( const FLASH_DESCRIPTOR_MAP * ) ( ( UINT8 * ) descriptor + sizeof ( FLASH_DESCRIPTOR_HEADER ) ) ;
const FLASH_DESCRIPTOR_UPPER_MAP * upperMap = ( const FLASH_DESCRIPTOR_UPPER_MAP * ) ( ( UINT8 * ) descriptor + FLASH_DESCRIPTOR_UPPER_MAP_BASE ) ;
2015-12-12 17:59:38 +08:00
// Check sanity of base values
if ( descriptorMap - > MasterBase > FLASH_DESCRIPTOR_MAX_BASE
| | descriptorMap - > MasterBase = = descriptorMap - > RegionBase
| | descriptorMap - > MasterBase = = descriptorMap - > ComponentBase ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: invalid descriptor master base %02Xh " , __FUNCTION__ , descriptorMap - > MasterBase ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_FLASH_DESCRIPTOR ;
2015-12-12 17:59:38 +08:00
}
if ( descriptorMap - > RegionBase > FLASH_DESCRIPTOR_MAX_BASE
| | descriptorMap - > RegionBase = = descriptorMap - > ComponentBase ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: invalid descriptor region base %02Xh " , __FUNCTION__ , descriptorMap - > RegionBase ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_FLASH_DESCRIPTOR ;
2015-12-12 17:59:38 +08:00
}
if ( descriptorMap - > ComponentBase > FLASH_DESCRIPTOR_MAX_BASE ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: invalid descriptor component base %02Xh " , __FUNCTION__ , descriptorMap - > ComponentBase ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_FLASH_DESCRIPTOR ;
2015-12-12 17:59:38 +08:00
}
2018-04-30 13:33:19 +08:00
const FLASH_DESCRIPTOR_REGION_SECTION * regionSection = ( const FLASH_DESCRIPTOR_REGION_SECTION * ) calculateAddress8 ( ( UINT8 * ) descriptor , descriptorMap - > RegionBase ) ;
const FLASH_DESCRIPTOR_COMPONENT_SECTION * componentSection = ( const FLASH_DESCRIPTOR_COMPONENT_SECTION * ) calculateAddress8 ( ( UINT8 * ) descriptor , descriptorMap - > ComponentBase ) ;
2015-09-13 04:53:07 +08:00
2018-05-07 05:23:04 +08:00
UINT8 descriptorVersion = 2 ;
2018-05-06 20:22:25 +08:00
// Check descriptor version by getting hardcoded value of FlashParameters.ReadClockFrequency
2018-05-07 05:23:04 +08:00
if ( componentSection - > FlashParameters . ReadClockFrequency = = FLASH_FREQUENCY_20MHZ )
2015-09-13 04:53:07 +08:00
descriptorVersion = 1 ;
2016-02-02 09:08:08 +08:00
// Regions
2016-03-01 15:20:44 +08:00
std : : vector < REGION_INFO > regions ;
2016-02-02 09:08:08 +08:00
2015-03-13 14:48:53 +08:00
// ME region
2016-02-02 09:08:08 +08:00
REGION_INFO me ;
me . type = Subtypes : : MeRegion ;
me . offset = 0 ;
me . length = 0 ;
2015-03-13 14:48:53 +08:00
if ( regionSection - > MeLimit ) {
2016-02-02 09:08:08 +08:00
me . offset = calculateRegionOffset ( regionSection - > MeBase ) ;
me . length = calculateRegionSize ( regionSection - > MeBase , regionSection - > MeLimit ) ;
me . data = intelImage . mid ( me . offset , me . length ) ;
2016-03-01 15:20:44 +08:00
regions . push_back ( me ) ;
2015-03-13 14:48:53 +08:00
}
2015-09-13 04:53:07 +08:00
2015-03-13 14:48:53 +08:00
// BIOS region
if ( regionSection - > BiosLimit ) {
2017-12-11 09:56:00 +08:00
REGION_INFO bios ;
bios . type = Subtypes : : BiosRegion ;
2016-02-02 09:08:08 +08:00
bios . offset = calculateRegionOffset ( regionSection - > BiosBase ) ;
bios . length = calculateRegionSize ( regionSection - > BiosBase , regionSection - > BiosLimit ) ;
2015-03-13 14:48:53 +08:00
// Check for Gigabyte specific descriptor map
2016-02-02 09:08:08 +08:00
if ( bios . length = = ( UINT32 ) intelImage . size ( ) ) {
if ( ! me . offset ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: can't determine BIOS region start from Gigabyte-specific descriptor " , __FUNCTION__ ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_FLASH_DESCRIPTOR ;
2015-03-13 14:48:53 +08:00
}
2016-02-02 09:08:08 +08:00
// Use ME region end as BIOS region offset
bios . offset = me . offset + me . length ;
bios . length = ( UINT32 ) intelImage . size ( ) - bios . offset ;
bios . data = intelImage . mid ( bios . offset , bios . length ) ;
2015-10-05 16:21:33 +08:00
}
// Normal descriptor map
else {
2016-02-02 09:08:08 +08:00
bios . data = intelImage . mid ( bios . offset , bios . length ) ;
2015-03-13 14:48:53 +08:00
}
2016-02-02 09:08:08 +08:00
2016-03-01 15:20:44 +08:00
regions . push_back ( bios ) ;
2015-03-13 14:48:53 +08:00
}
else {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: descriptor parsing failed, BIOS region not found in descriptor " , __FUNCTION__ ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_FLASH_DESCRIPTOR ;
2015-03-13 14:48:53 +08:00
}
2017-12-11 09:56:00 +08:00
// Add all other regions
for ( UINT8 i = Subtypes : : GbeRegion ; i < = Subtypes : : PttRegion ; i + + ) {
if ( descriptorVersion = = 1 & & i = = Subtypes : : MicrocodeRegion )
2018-05-07 05:23:04 +08:00
break ; // Do not parse Microcode and other following regions for legacy descriptors
2017-12-11 09:56:00 +08:00
const UINT16 * RegionBase = ( ( const UINT16 * ) regionSection ) + 2 * i ;
const UINT16 * RegionLimit = ( ( const UINT16 * ) regionSection ) + 2 * i + 1 ;
if ( * RegionLimit & & ! ( * RegionBase = = 0xFFFF & & * RegionLimit = = 0xFFFF ) ) {
REGION_INFO region ;
region . type = i ;
region . offset = calculateRegionOffset ( * RegionBase ) ;
region . length = calculateRegionSize ( * RegionBase , * RegionLimit ) ;
if ( region . length ! = 0 ) {
region . data = intelImage . mid ( region . offset , region . length ) ;
regions . push_back ( region ) ;
}
2015-09-13 04:53:07 +08:00
}
}
2016-02-02 09:08:08 +08:00
// Sort regions in ascending order
2016-03-21 06:59:03 +08:00
std : : sort ( regions . begin ( ) , regions . end ( ) ) ;
2016-02-02 09:08:08 +08:00
// Check for intersections and paddings between regions
REGION_INFO region ;
// Check intersection with the descriptor
2016-03-01 15:20:44 +08:00
if ( regions . front ( ) . offset < FLASH_DESCRIPTOR_SIZE ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: " , __FUNCTION__ ) + itemSubtypeToUString ( Types : : Region , regions . front ( ) . type )
2016-06-26 11:54:21 +08:00
+ UString ( " region has intersection with flash descriptor " ) ,
index ) ;
return U_INVALID_FLASH_DESCRIPTOR ;
2015-03-13 14:48:53 +08:00
}
2016-02-02 09:08:08 +08:00
// Check for padding between descriptor and the first region
2016-03-01 15:20:44 +08:00
else if ( regions . front ( ) . offset > FLASH_DESCRIPTOR_SIZE ) {
2016-02-02 09:08:08 +08:00
region . offset = FLASH_DESCRIPTOR_SIZE ;
2016-03-01 15:20:44 +08:00
region . length = regions . front ( ) . offset - FLASH_DESCRIPTOR_SIZE ;
2016-02-02 09:08:08 +08:00
region . data = intelImage . mid ( region . offset , region . length ) ;
region . type = getPaddingType ( region . data ) ;
2016-03-01 16:52:25 +08:00
regions . insert ( regions . begin ( ) , region ) ;
2016-02-02 09:08:08 +08:00
}
// Check for intersections/paddings between regions
2016-03-01 15:20:44 +08:00
for ( size_t i = 1 ; i < regions . size ( ) ; i + + ) {
2016-02-02 09:08:08 +08:00
UINT32 previousRegionEnd = regions [ i - 1 ] . offset + regions [ i - 1 ] . length ;
// Check that current region is fully present in the image
2016-12-23 06:34:24 +08:00
if ( ( UINT64 ) regions [ i ] . offset + ( UINT64 ) regions [ i ] . length > ( UINT64 ) intelImage . size ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: " , __FUNCTION__ ) + itemSubtypeToUString ( Types : : Region , regions [ i ] . type )
2016-12-23 06:34:24 +08:00
+ UString ( " region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image " ) ,
2016-06-26 11:54:21 +08:00
index ) ;
return U_TRUNCATED_IMAGE ;
2016-02-02 09:08:08 +08:00
}
// Check for intersection with previous region
if ( regions [ i ] . offset < previousRegionEnd ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: " , __FUNCTION__ ) + itemSubtypeToUString ( Types : : Region , regions [ i ] . type )
2016-06-26 11:54:21 +08:00
+ UString ( " region has intersection with " ) + itemSubtypeToUString ( Types : : Region , regions [ i - 1 ] . type ) + UString ( " region " ) ,
index ) ;
return U_INVALID_FLASH_DESCRIPTOR ;
2016-02-02 09:08:08 +08:00
}
// Check for padding between current and previous regions
else if ( regions [ i ] . offset > previousRegionEnd ) {
region . offset = previousRegionEnd ;
region . length = regions [ i ] . offset - previousRegionEnd ;
region . data = intelImage . mid ( region . offset , region . length ) ;
region . type = getPaddingType ( region . data ) ;
2016-03-01 16:52:25 +08:00
std : : vector < REGION_INFO > : : iterator iter = regions . begin ( ) ;
2016-12-23 06:34:24 +08:00
std : : advance ( iter , i ) ;
2016-03-01 16:52:25 +08:00
regions . insert ( iter , region ) ;
2016-02-02 09:08:08 +08:00
}
2015-09-13 04:53:07 +08:00
}
2016-02-02 09:08:08 +08:00
// Check for padding after the last region
2016-12-23 06:34:24 +08:00
if ( ( UINT64 ) regions . back ( ) . offset + ( UINT64 ) regions . back ( ) . length < ( UINT64 ) intelImage . size ( ) ) {
2016-03-01 15:20:44 +08:00
region . offset = regions . back ( ) . offset + regions . back ( ) . length ;
2016-02-02 09:08:08 +08:00
region . length = intelImage . size ( ) - region . offset ;
region . data = intelImage . mid ( region . offset , region . length ) ;
region . type = getPaddingType ( region . data ) ;
2016-03-01 15:20:44 +08:00
regions . push_back ( region ) ;
2015-09-13 04:53:07 +08:00
}
2016-02-02 09:08:08 +08:00
2015-03-13 14:48:53 +08:00
// Region map is consistent
// Intel image
2016-06-26 11:54:21 +08:00
UString name ( " Intel image " ) ;
UString info = usprintf ( " Full size: %Xh (%u) \n Flash chips: %u \n Regions: %u \n Masters: %u \n PCH straps: %u \n PROC straps: %u " ,
intelImage . size ( ) , intelImage . size ( ) ,
descriptorMap - > NumberOfFlashChips + 1 , //
descriptorMap - > NumberOfRegions + 1 , // Zero-based numbers in storage
descriptorMap - > NumberOfMasters + 1 , //
descriptorMap - > NumberOfPchStraps ,
descriptorMap - > NumberOfProcStraps ) ;
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
// Set image base
2019-01-07 21:05:57 +08:00
imageBase = model - > base ( parent ) + localOffset ;
2018-10-08 17:58:12 +08:00
2015-03-13 14:48:53 +08:00
// Add Intel image tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Image , Subtypes : : IntelImage , name , UString ( ) , info , UByteArray ( ) , intelImage , UByteArray ( ) , Fixed , parent ) ;
2015-03-13 14:48:53 +08:00
// Descriptor
// Get descriptor info
2016-06-26 11:54:21 +08:00
UByteArray body = intelImage . left ( FLASH_DESCRIPTOR_SIZE ) ;
name = UString ( " Descriptor region " ) ;
2018-04-30 13:33:19 +08:00
info = usprintf ( " ReservedVector: \n %02X %02X %02X %02X %02X %02X %02X %02X \n "
" %02X %02X %02X %02X %02X %02X %02X %02X \n Full size: %Xh (%u) " ,
descriptor - > ReservedVector [ 0 ] , descriptor - > ReservedVector [ 1 ] , descriptor - > ReservedVector [ 2 ] , descriptor - > ReservedVector [ 3 ] ,
descriptor - > ReservedVector [ 4 ] , descriptor - > ReservedVector [ 5 ] , descriptor - > ReservedVector [ 6 ] , descriptor - > ReservedVector [ 7 ] ,
descriptor - > ReservedVector [ 8 ] , descriptor - > ReservedVector [ 9 ] , descriptor - > ReservedVector [ 10 ] , descriptor - > ReservedVector [ 11 ] ,
descriptor - > ReservedVector [ 12 ] , descriptor - > ReservedVector [ 13 ] , descriptor - > ReservedVector [ 14 ] , descriptor - > ReservedVector [ 15 ] ,
FLASH_DESCRIPTOR_SIZE , FLASH_DESCRIPTOR_SIZE ) ;
2016-02-02 09:08:08 +08:00
// Add offsets of actual regions
2016-03-01 15:20:44 +08:00
for ( size_t i = 0 ; i < regions . size ( ) ; i + + ) {
2016-02-02 09:08:08 +08:00
if ( regions [ i ] . type ! = Subtypes : : ZeroPadding & & regions [ i ] . type ! = Subtypes : : OnePadding & & regions [ i ] . type ! = Subtypes : : DataPadding )
2016-06-26 16:05:45 +08:00
info + = UString ( " \n " ) + itemSubtypeToUString ( Types : : Region , regions [ i ] . type )
2016-10-28 00:31:15 +08:00
+ usprintf ( " region offset: %Xh " , regions [ i ] . offset + localOffset ) ;
2015-03-13 14:48:53 +08:00
}
// Region access settings
2015-09-13 04:53:07 +08:00
if ( descriptorVersion = = 1 ) {
2018-04-30 13:33:19 +08:00
const FLASH_DESCRIPTOR_MASTER_SECTION * masterSection = ( const FLASH_DESCRIPTOR_MASTER_SECTION * ) calculateAddress8 ( ( UINT8 * ) descriptor , descriptorMap - > MasterBase ) ;
2016-06-26 11:54:21 +08:00
info + = UString ( " \n Region access settings: " ) ;
info + = usprintf ( " \n BIOS: %02Xh %02Xh ME: %02Xh %02Xh \n GbE: %02Xh %02Xh " ,
masterSection - > BiosRead ,
masterSection - > BiosWrite ,
masterSection - > MeRead ,
masterSection - > MeWrite ,
masterSection - > GbeRead ,
masterSection - > GbeWrite ) ;
2015-09-13 04:53:07 +08:00
// BIOS access table
2016-06-26 11:54:21 +08:00
info + = UString ( " \n BIOS access table: " )
+ UString ( " \n Read Write " )
+ usprintf ( " \n Desc %s %s " , masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? " Yes " : " No " ) ;
info + = UString ( " \n BIOS Yes Yes " )
+ usprintf ( " \n ME %s %s " , masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ) ;
info + = usprintf ( " \n GbE %s %s " , masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ) ;
info + = usprintf ( " \n PDR %s %s " , masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " ) ;
2015-09-13 04:53:07 +08:00
}
2018-05-07 05:23:04 +08:00
else if ( descriptorVersion = = 2 ) {
2018-04-30 13:33:19 +08:00
const FLASH_DESCRIPTOR_MASTER_SECTION_V2 * masterSection = ( const FLASH_DESCRIPTOR_MASTER_SECTION_V2 * ) calculateAddress8 ( ( UINT8 * ) descriptor , descriptorMap - > MasterBase ) ;
2016-06-26 16:05:45 +08:00
info + = UString ( " \n Region access settings: " ) ;
info + = usprintf ( " \n BIOS: %03Xh %03Xh ME: %03Xh %03Xh \n GbE: %03Xh %03Xh EC: %03Xh %03Xh " ,
2016-06-26 11:54:21 +08:00
masterSection - > BiosRead ,
masterSection - > BiosWrite ,
masterSection - > MeRead ,
masterSection - > MeWrite ,
masterSection - > GbeRead ,
masterSection - > GbeWrite ,
masterSection - > EcRead ,
masterSection - > EcWrite ) ;
2015-09-13 04:53:07 +08:00
// BIOS access table
2016-06-26 11:54:21 +08:00
info + = UString ( " \n BIOS access table: " )
+ UString ( " \n Read Write " )
+ usprintf ( " \n Desc %s %s " ,
masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_DESC ? " Yes " : " No " ) ;
info + = UString ( " \n BIOS Yes Yes " )
+ usprintf ( " \n ME %s %s " ,
masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ) ;
info + = usprintf ( " \n GbE %s %s " ,
masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ) ;
info + = usprintf ( " \n PDR %s %s " ,
masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " ) ;
info + = usprintf ( " \n EC %s %s " ,
masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_EC ? " Yes " : " No " ) ;
2018-05-07 05:23:04 +08:00
// Prepend descriptor version if present
if ( descriptorMap - > DescriptorVersion ! = FLASH_DESCRIPTOR_VERSION_INVALID ) {
const FLASH_DESCRIPTOR_VERSION * version = ( const FLASH_DESCRIPTOR_VERSION * ) & descriptorMap - > DescriptorVersion ;
UString versionStr = usprintf ( " Flash descriptor version: %d.%d " , version - > Major , version - > Minor ) ;
if ( version - > Major ! = FLASH_DESCRIPTOR_VERSION_MAJOR | | version - > Minor ! = FLASH_DESCRIPTOR_VERSION_MINOR ) {
versionStr + = " , unknown " ;
msg ( usprintf ( " %s: unknown flash descriptor version %d.%d " , __FUNCTION__ , version - > Major , version - > Minor ) ) ;
}
info = versionStr + " \n " + info ;
}
2015-09-13 04:53:07 +08:00
}
2015-03-13 14:48:53 +08:00
// VSCC table
2018-04-30 13:33:19 +08:00
const VSCC_TABLE_ENTRY * vsccTableEntry = ( const VSCC_TABLE_ENTRY * ) ( ( UINT8 * ) descriptor + ( ( UINT16 ) upperMap - > VsccTableBase < < 4 ) ) ;
2016-06-26 11:54:21 +08:00
info + = UString ( " \n Flash chips in VSCC table: " ) ;
2015-03-13 14:48:53 +08:00
UINT8 vsscTableSize = upperMap - > VsccTableSize * sizeof ( UINT32 ) / sizeof ( VSCC_TABLE_ENTRY ) ;
2017-11-06 15:10:06 +08:00
for ( UINT8 i = 0 ; i < vsscTableSize ; i + + ) {
2018-01-23 16:00:03 +08:00
UString jedecId = jedecIdToUString ( vsccTableEntry - > VendorId , vsccTableEntry - > DeviceId0 , vsccTableEntry - > DeviceId1 ) ;
2017-12-11 09:56:00 +08:00
info + = usprintf ( " \n %02X%02X%02X ( " , vsccTableEntry - > VendorId , vsccTableEntry - > DeviceId0 , vsccTableEntry - > DeviceId1 )
+ jedecId
2016-10-10 14:05:04 +08:00
+ UString ( " ) " ) ;
2018-01-23 16:00:03 +08:00
if ( jedecId = = UString ( " Unknown " ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: SPI flash with unknown JEDEC ID %02X%02X%02X found in VSCC table " , __FUNCTION__ ,
vsccTableEntry - > VendorId , vsccTableEntry - > DeviceId0 , vsccTableEntry - > DeviceId1 ) , index ) ;
2018-01-23 16:00:03 +08:00
}
2015-03-13 14:48:53 +08:00
vsccTableEntry + + ;
}
// Add descriptor tree item
2019-01-07 21:05:57 +08:00
UModelIndex regionIndex = model - > addItem ( localOffset , Types : : Region , Subtypes : : DescriptorRegion , name , UString ( ) , info , UByteArray ( ) , body , UByteArray ( ) , Fixed , index ) ;
2017-12-11 09:56:00 +08:00
2018-10-08 17:58:12 +08:00
2015-03-13 14:48:53 +08:00
// Parse regions
2018-07-13 03:56:51 +08:00
USTATUS result = U_SUCCESS ;
USTATUS parseResult = U_SUCCESS ;
2016-03-01 15:20:44 +08:00
for ( size_t i = 0 ; i < regions . size ( ) ; i + + ) {
region = regions [ i ] ;
2016-02-02 09:08:08 +08:00
switch ( region . type ) {
case Subtypes : : BiosRegion :
result = parseBiosRegion ( region . data , region . offset , index , regionIndex ) ;
break ;
case Subtypes : : MeRegion :
result = parseMeRegion ( region . data , region . offset , index , regionIndex ) ;
break ;
case Subtypes : : GbeRegion :
result = parseGbeRegion ( region . data , region . offset , index , regionIndex ) ;
break ;
case Subtypes : : PdrRegion :
result = parsePdrRegion ( region . data , region . offset , index , regionIndex ) ;
break ;
2017-12-11 09:56:00 +08:00
case Subtypes : : DevExp1Region :
2019-09-05 08:07:18 +08:00
result = parseDevExp1Region ( region . data , region . offset , index , regionIndex ) ;
break ;
2017-12-11 09:56:00 +08:00
case Subtypes : : Bios2Region :
case Subtypes : : MicrocodeRegion :
case Subtypes : : EcRegion :
case Subtypes : : DevExp2Region :
case Subtypes : : IeRegion :
case Subtypes : : Tgbe1Region :
case Subtypes : : Tgbe2Region :
2016-02-02 09:08:08 +08:00
case Subtypes : : Reserved1Region :
case Subtypes : : Reserved2Region :
2017-12-11 09:56:00 +08:00
case Subtypes : : PttRegion :
result = parseGenericRegion ( region . type , region . data , region . offset , index , regionIndex ) ;
2016-02-02 09:08:08 +08:00
break ;
case Subtypes : : ZeroPadding :
case Subtypes : : OnePadding :
case Subtypes : : DataPadding : {
// Add padding between regions
2016-06-26 11:54:21 +08:00
UByteArray padding = intelImage . mid ( region . offset , region . length ) ;
2015-09-01 03:34:42 +08:00
2016-02-02 09:08:08 +08:00
// Get info
2016-06-26 11:54:21 +08:00
name = UString ( " Padding " ) ;
2016-06-26 16:05:45 +08:00
info = usprintf ( " Full size: %Xh (%u) " ,
2016-06-26 11:54:21 +08:00
padding . size ( ) , padding . size ( ) ) ;
2015-09-01 03:34:42 +08:00
2016-02-02 09:08:08 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
regionIndex = model - > addItem ( region . offset , Types : : Padding , getPaddingType ( padding ) , name , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
2016-06-26 11:54:21 +08:00
result = U_SUCCESS ;
2016-02-02 09:08:08 +08:00
} break ;
default :
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: region of unknown type found " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
result = U_INVALID_FLASH_DESCRIPTOR ;
2016-02-02 09:08:08 +08:00
}
// Store the first failed result as a final result
2016-10-28 00:31:15 +08:00
if ( ! parseResult & & result ) {
2016-02-02 09:08:08 +08:00
parseResult = result ;
2016-10-28 00:31:15 +08:00
}
2015-06-20 02:26:45 +08:00
}
2016-02-02 09:08:08 +08:00
return parseResult ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseGbeRegion ( const UByteArray & gbe , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Check sanity
if ( gbe . isEmpty ( ) )
2016-06-26 11:54:21 +08:00
return U_EMPTY_REGION ;
2015-12-12 17:59:38 +08:00
if ( ( UINT32 ) gbe . size ( ) < GBE_VERSION_OFFSET + sizeof ( GBE_VERSION ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_REGION ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name ( " GbE region " ) ;
2015-03-13 14:48:53 +08:00
const GBE_MAC_ADDRESS * mac = ( const GBE_MAC_ADDRESS * ) gbe . constData ( ) ;
const GBE_VERSION * version = ( const GBE_VERSION * ) ( gbe . constData ( ) + GBE_VERSION_OFFSET ) ;
2016-06-26 11:54:21 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n MAC: %02X:%02X:%02X:%02X:%02X:%02X \n Version: %u.%u " ,
gbe . size ( ) , gbe . size ( ) ,
mac - > vendor [ 0 ] , mac - > vendor [ 1 ] , mac - > vendor [ 2 ] ,
mac - > device [ 0 ] , mac - > device [ 1 ] , mac - > device [ 2 ] ,
version - > major ,
version - > minor ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Region , Subtypes : : GbeRegion , name , UString ( ) , info , UByteArray ( ) , gbe , UByteArray ( ) , Fixed , parent ) ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseMeRegion ( const UByteArray & me , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Check sanity
if ( me . isEmpty ( ) )
2016-06-26 11:54:21 +08:00
return U_EMPTY_REGION ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name ( " ME region " ) ;
UString info = usprintf ( " Full size: %Xh (%u) " , me . size ( ) , me . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Parse region
bool versionFound = true ;
bool emptyRegion = false ;
// Check for empty region
2016-07-05 23:22:03 +08:00
if ( me . size ( ) = = me . count ( ' \xFF ' ) | | me . size ( ) = = me . count ( ' \x00 ' ) ) {
2015-03-13 14:48:53 +08:00
// Further parsing not needed
emptyRegion = true ;
2016-06-26 11:54:21 +08:00
info + = ( " \n State: empty " ) ;
2015-03-13 14:48:53 +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 ) {
2016-06-26 11:54:21 +08:00
info + = ( " \n Version: unknown " ) ;
2015-03-13 14:48:53 +08:00
versionFound = false ;
}
}
2015-12-12 17:59:38 +08:00
// Check sanity
if ( ( UINT32 ) me . size ( ) < ( UINT32 ) versionOffset + sizeof ( ME_VERSION ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_REGION ;
2015-12-12 17:59:38 +08:00
2015-03-13 14:48:53 +08:00
// Add version information
if ( versionFound ) {
const ME_VERSION * version = ( const ME_VERSION * ) ( me . constData ( ) + versionOffset ) ;
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n Version: %u.%u.%u.%u " ,
2018-10-08 17:58:12 +08:00
version - > Major ,
version - > Minor ,
version - > Bugfix ,
version - > Build ) ;
2015-03-13 14:48:53 +08:00
}
}
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Region , Subtypes : : MeRegion , name , UString ( ) , info , UByteArray ( ) , me , UByteArray ( ) , Fixed , parent ) ;
2015-03-13 14:48:53 +08:00
// Show messages
if ( emptyRegion ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: ME region is empty " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
}
else if ( ! versionFound ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: ME version is unknown, it can be damaged " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
}
2016-12-23 06:34:24 +08:00
else {
2017-12-11 09:56:00 +08:00
meParser - > parseMeRegionBody ( index ) ;
2016-12-23 06:34:24 +08:00
}
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parsePdrRegion ( const UByteArray & pdr , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Check sanity
if ( pdr . isEmpty ( ) )
2016-06-26 11:54:21 +08:00
return U_EMPTY_REGION ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name ( " PDR region " ) ;
UString info = usprintf ( " Full size: %Xh (%u) " , pdr . size ( ) , pdr . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Region , Subtypes : : PdrRegion , name , UString ( ) , info , UByteArray ( ) , pdr , UByteArray ( ) , Fixed , parent ) ;
2015-03-13 14:48:53 +08:00
// Parse PDR region as BIOS space
2018-07-13 03:56:51 +08:00
USTATUS result = parseRawArea ( index ) ;
2019-07-25 01:30:59 +08:00
if ( result & & result ! = U_VOLUMES_NOT_FOUND & & result ! = U_INVALID_VOLUME & & result ! = U_STORES_NOT_FOUND )
2015-03-13 14:48:53 +08:00
return result ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2019-09-05 08:07:18 +08:00
USTATUS FfsParser : : parseDevExp1Region ( const UByteArray & devExp1 , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
{
// Check sanity
if ( devExp1 . isEmpty ( ) )
return U_EMPTY_REGION ;
// Get info
UString name ( " DevExp1 region " ) ;
UString info = usprintf ( " Full size: %Xh (%u) " , devExp1 . size ( ) , devExp1 . size ( ) ) ;
bool emptyRegion = false ;
// Check for empty region
if ( devExp1 . size ( ) = = devExp1 . count ( ' \xFF ' ) | | devExp1 . size ( ) = = devExp1 . count ( ' \x00 ' ) ) {
// Further parsing not needed
emptyRegion = true ;
info + = ( " \n State: empty " ) ;
}
// Add tree item
index = model - > addItem ( localOffset , Types : : Region , Subtypes : : DevExp1Region , name , UString ( ) , info , UByteArray ( ) , devExp1 , UByteArray ( ) , Fixed , parent ) ;
if ( ! emptyRegion ) {
meParser - > parseMeRegionBody ( index ) ;
}
return U_SUCCESS ;
}
2017-12-11 09:56:00 +08:00
USTATUS FfsParser : : parseGenericRegion ( const UINT8 subtype , const UByteArray & region , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2015-09-13 04:53:07 +08:00
{
// Check sanity
2016-02-02 09:08:08 +08:00
if ( region . isEmpty ( ) )
2016-06-26 11:54:21 +08:00
return U_EMPTY_REGION ;
2015-09-13 04:53:07 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = itemSubtypeToUString ( Types : : Region , subtype ) + UString ( " region " ) ;
UString info = usprintf ( " Full size: %Xh (%u) " , region . size ( ) , region . size ( ) ) ;
2015-09-13 04:53:07 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Region , subtype , name , UString ( ) , info , UByteArray ( ) , region , UByteArray ( ) , Fixed , parent ) ;
2015-09-13 04:53:07 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-09-13 04:53:07 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseBiosRegion ( const UByteArray & bios , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( bios . isEmpty ( ) )
2016-06-26 11:54:21 +08:00
return U_EMPTY_REGION ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name ( " BIOS region " ) ;
UString info = usprintf ( " Full size: %Xh (%u) " , bios . size ( ) , bios . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Region , Subtypes : : BiosRegion , name , UString ( ) , info , UByteArray ( ) , bios , UByteArray ( ) , Fixed , parent ) ;
2019-08-20 02:36:02 +08:00
2016-04-17 07:25:44 +08:00
return parseRawArea ( index ) ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseRawArea ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2016-04-17 07:25:44 +08:00
// Get item data
2016-06-26 11:54:21 +08:00
UByteArray data = model - > body ( index ) ;
2018-10-08 17:58:12 +08:00
UINT32 headerSize = model - > header ( index ) . size ( ) ;
2016-04-17 07:25:44 +08:00
2016-06-26 11:54:21 +08:00
USTATUS result ;
2018-10-08 17:58:12 +08:00
UString name ;
UString info ;
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
// Search for the first item
UINT8 prevItemType = 0 ;
UINT32 prevItemOffset = 0 ;
UINT32 prevItemSize = 0 ;
UINT32 prevItemAltSize = 0 ;
result = findNextRawAreaItem ( index , 0 , prevItemType , prevItemOffset , prevItemSize , prevItemAltSize ) ;
if ( result ) {
// No need to parse further
return U_SUCCESS ;
}
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
// Set base of protected regions to be the first volume
if ( model - > type ( index ) = = Types : : Region
2019-01-07 21:05:57 +08:00
& & model - > subtype ( index ) = = Subtypes : : BiosRegion ) {
bgProtectedRegionsBase = ( UINT64 ) model - > base ( index ) + prevItemOffset ;
}
2017-10-12 13:59:23 +08:00
2018-10-08 17:58:12 +08:00
// First item is not at the beginning of this raw area
if ( prevItemOffset > 0 ) {
2015-03-13 14:48:53 +08:00
// Get info
2018-10-08 17:58:12 +08:00
UByteArray padding = data . left ( prevItemOffset ) ;
2016-06-26 11:54:21 +08:00
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " , padding . size ( ) , padding . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
model - > addItem ( headerSize , Types : : Padding , getPaddingType ( padding ) , name , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
2015-03-13 14:48:53 +08:00
}
2018-10-08 17:58:12 +08:00
// Search for and parse all items
UINT8 itemType = prevItemType ;
UINT32 itemOffset = prevItemOffset ;
UINT32 itemSize = prevItemSize ;
UINT32 itemAltSize = prevItemAltSize ;
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
while ( ! result ) {
// Padding between items
if ( itemOffset > prevItemOffset + prevItemSize ) {
UINT32 paddingOffset = prevItemOffset + prevItemSize ;
UINT32 paddingSize = itemOffset - paddingOffset ;
2016-06-26 11:54:21 +08:00
UByteArray padding = data . mid ( paddingOffset , paddingSize ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " , padding . size ( ) , padding . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
model - > addItem ( headerSize + paddingOffset , Types : : Padding , getPaddingType ( padding ) , name , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
2015-03-13 14:48:53 +08:00
}
2015-12-12 17:59:38 +08:00
2018-10-08 17:58:12 +08:00
// Check that item is fully present in input
if ( itemSize > ( UINT32 ) data . size ( ) | | itemOffset + itemSize > ( UINT32 ) data . size ( ) ) {
// Mark the rest as padding and finish parsing
UByteArray padding = data . mid ( itemOffset ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " , padding . size ( ) , padding . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
UModelIndex paddingIndex = model - > addItem ( headerSize + itemOffset , Types : : Padding , getPaddingType ( padding ) , name , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: one of volumes inside overlaps the end of data " , __FUNCTION__ ) , paddingIndex ) ;
2015-03-13 14:48:53 +08:00
// Update variables
2018-10-08 17:58:12 +08:00
prevItemOffset = itemOffset ;
prevItemSize = padding . size ( ) ;
2015-03-13 14:48:53 +08:00
break ;
}
2016-10-28 00:31:15 +08:00
2015-03-13 14:48:53 +08:00
// Parse current volume's header
2018-10-08 17:58:12 +08:00
if ( itemType = = Types : : Volume ) {
UModelIndex volumeIndex ;
UByteArray volume = data . mid ( itemOffset , itemSize ) ;
result = parseVolumeHeader ( volume , headerSize + itemOffset , index , volumeIndex ) ;
if ( result ) {
msg ( usprintf ( " %s: volume header parsing failed with error " , __FUNCTION__ ) + errorCodeToUString ( result ) , index ) ;
} else {
// Show messages
if ( itemSize ! = itemAltSize )
msg ( usprintf ( " %s: volume size stored in header %Xh differs from calculated using block map %Xh " , __FUNCTION__ ,
itemSize , itemAltSize ) ,
volumeIndex ) ;
}
}
else if ( itemType = = Types : : Microcode ) {
UModelIndex microcodeIndex ;
UByteArray microcode = data . mid ( itemOffset , itemSize ) ;
result = parseIntelMicrocodeHeader ( microcode , headerSize + itemOffset , index , microcodeIndex ) ;
if ( result ) {
msg ( usprintf ( " %s: microcode header parsing failed with error " , __FUNCTION__ ) + errorCodeToUString ( result ) , index ) ;
}
}
2019-08-20 02:36:02 +08:00
else if ( itemType = = Types : : BpdtStore ) {
UByteArray bpdtStore = data . mid ( itemOffset , itemSize ) ;
// Get info
name = UString ( " BPDT region " ) ;
info = usprintf ( " Full size: %Xh (%u) " , bpdtStore . size ( ) , bpdtStore . size ( ) ) ;
// Add tree item
UModelIndex bpdtIndex = model - > addItem ( headerSize + itemOffset , Types : : BpdtStore , 0 , name , UString ( ) , info , UByteArray ( ) , bpdtStore , UByteArray ( ) , Fixed , index ) ;
// Parse BPDT region
UModelIndex bpdtPtIndex ;
result = parseBpdtRegion ( bpdtStore , 0 , 0 , bpdtIndex , bpdtPtIndex ) ;
if ( result ) {
msg ( usprintf ( " %s: BPDT store parsing failed with error " , __FUNCTION__ ) + errorCodeToUString ( result ) , index ) ;
}
}
2018-10-08 17:58:12 +08:00
else {
return U_UNKNOWN_ITEM_TYPE ;
2015-03-13 14:48:53 +08:00
}
2018-10-08 17:58:12 +08:00
// Go to next item
prevItemOffset = itemOffset ;
prevItemSize = itemSize ;
prevItemType = itemType ;
result = findNextRawAreaItem ( index , itemOffset + prevItemSize , itemType , itemOffset , itemSize , itemAltSize ) ;
2019-07-25 01:30:59 +08:00
// Silence value not used after assignment warning
( void ) prevItemType ;
2015-03-13 14:48:53 +08:00
}
2016-03-28 21:03:32 +08:00
// Padding at the end of RAW area
2018-10-08 17:58:12 +08:00
itemOffset = prevItemOffset + prevItemSize ;
if ( ( UINT32 ) data . size ( ) > itemOffset ) {
UByteArray padding = data . mid ( itemOffset ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " , padding . size ( ) , padding . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
model - > addItem ( headerSize + itemOffset , Types : : Padding , getPaddingType ( padding ) , name , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
2015-03-13 14:48:53 +08:00
}
2015-09-13 22:36:43 +08:00
// Parse bodies
2015-03-13 14:48:53 +08:00
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2016-06-26 11:54:21 +08:00
UModelIndex current = index . child ( i , 0 ) ;
2015-03-13 14:48:53 +08:00
switch ( model - > type ( current ) ) {
case Types : : Volume :
parseVolumeBody ( current ) ;
break ;
2018-10-08 17:58:12 +08:00
case Types : : Microcode :
// Parsing already done
break ;
2019-08-20 02:36:02 +08:00
case Types : : BpdtStore :
// Parsing already done
break ;
case Types : : BpdtPartition :
// Parsing already done
break ;
2015-03-13 14:48:53 +08:00
case Types : : Padding :
// No parsing required
break ;
default :
2016-06-26 11:54:21 +08:00
return U_UNKNOWN_ITEM_TYPE ;
2015-03-13 14:48:53 +08:00
}
}
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseVolumeHeader ( const UByteArray & volume , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( volume . isEmpty ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2015-12-12 17:59:38 +08:00
// Check that there is space for the volume header
2019-08-18 08:40:37 +08:00
if ( ( UINT32 ) volume . size ( ) < sizeof ( EFI_FIRMWARE_VOLUME_HEADER ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: input volume size %Xh (%u) is smaller than volume header size 40h (64) " , __FUNCTION__ , volume . size ( ) , volume . size ( ) ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_VOLUME ;
2015-12-12 17:59:38 +08:00
}
2015-03-13 14:48:53 +08:00
// Populate volume header
const EFI_FIRMWARE_VOLUME_HEADER * volumeHeader = ( const EFI_FIRMWARE_VOLUME_HEADER * ) ( volume . constData ( ) ) ;
2015-12-12 17:59:38 +08:00
// Check sanity of HeaderLength value
if ( ( UINT32 ) ALIGN8 ( volumeHeader - > HeaderLength ) > ( UINT32 ) volume . size ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: volume header overlaps the end of data " , __FUNCTION__ ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_VOLUME ;
2015-12-12 17:59:38 +08:00
}
// Check sanity of ExtHeaderOffset value
if ( volumeHeader - > Revision > 1 & & volumeHeader - > ExtHeaderOffset
& & ( UINT32 ) ALIGN8 ( volumeHeader - > ExtHeaderOffset + sizeof ( EFI_FIRMWARE_VOLUME_EXT_HEADER ) ) > ( UINT32 ) volume . size ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: extended volume header overlaps the end of data " , __FUNCTION__ ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_VOLUME ;
2015-12-12 17:59:38 +08:00
}
2015-03-13 14:48:53 +08:00
// Calculate volume header size
UINT32 headerSize ;
2016-10-28 00:31:15 +08:00
EFI_GUID extendedHeaderGuid = { 0 , 0 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } } ;
2015-03-13 14:48:53 +08:00
bool hasExtendedHeader = false ;
if ( volumeHeader - > Revision > 1 & & volumeHeader - > ExtHeaderOffset ) {
hasExtendedHeader = true ;
const EFI_FIRMWARE_VOLUME_EXT_HEADER * extendedHeader = ( const EFI_FIRMWARE_VOLUME_EXT_HEADER * ) ( volume . constData ( ) + volumeHeader - > ExtHeaderOffset ) ;
headerSize = volumeHeader - > ExtHeaderOffset + extendedHeader - > ExtHeaderSize ;
extendedHeaderGuid = extendedHeader - > FvName ;
}
2018-10-08 17:58:12 +08:00
else {
2015-03-13 14:48:53 +08:00
headerSize = volumeHeader - > HeaderLength ;
2018-10-08 17:58:12 +08:00
}
2015-03-13 14:48:53 +08:00
// Extended header end can be unaligned
headerSize = ALIGN8 ( headerSize ) ;
// Check for volume structure to be known
bool isUnknown = true ;
2016-04-07 14:23:37 +08:00
bool isNvramVolume = false ;
2018-10-08 17:58:12 +08:00
bool isMicrocodeVolume = false ;
2015-03-13 14:48:53 +08:00
UINT8 ffsVersion = 0 ;
// Check for FFS v2 volume
2016-10-28 00:31:15 +08:00
UByteArray guid = UByteArray ( ( const char * ) & volumeHeader - > FileSystemGuid , sizeof ( EFI_GUID ) ) ;
2016-03-01 15:20:44 +08:00
if ( std : : find ( FFSv2Volumes . begin ( ) , FFSv2Volumes . end ( ) , guid ) ! = FFSv2Volumes . end ( ) ) {
2015-03-13 14:48:53 +08:00
isUnknown = false ;
ffsVersion = 2 ;
}
// Check for FFS v3 volume
2018-10-08 17:58:12 +08:00
else if ( std : : find ( FFSv3Volumes . begin ( ) , FFSv3Volumes . end ( ) , guid ) ! = FFSv3Volumes . end ( ) ) {
2015-03-13 14:48:53 +08:00
isUnknown = false ;
ffsVersion = 3 ;
}
2016-03-28 21:03:32 +08:00
// Check for VSS NVRAM volume
2018-10-08 17:58:12 +08:00
else if ( guid = = NVRAM_MAIN_STORE_VOLUME_GUID | | guid = = NVRAM_ADDITIONAL_STORE_VOLUME_GUID ) {
2016-03-28 21:03:32 +08:00
isUnknown = false ;
2016-04-07 14:23:37 +08:00
isNvramVolume = true ;
2016-03-28 21:03:32 +08:00
}
2018-10-08 17:58:12 +08:00
// Check for Microcode volume
else if ( guid = = EFI_APPLE_MICROCODE_VOLUME_GUID ) {
isUnknown = false ;
isMicrocodeVolume = true ;
headerSize = EFI_APPLE_MICROCODE_VOLUME_HEADER_SIZE ;
}
2016-03-28 21:03:32 +08:00
2015-03-13 14:48:53 +08:00
// Check volume revision and alignment
bool msgAlignmentBitsSet = false ;
bool msgUnaligned = false ;
bool msgUnknownRevision = false ;
2018-04-30 13:33:19 +08:00
UINT32 alignment = 0x10000 ; // Default volume alignment is 64K
2015-03-13 14:48:53 +08:00
if ( volumeHeader - > Revision = = 1 ) {
// Acquire alignment capability bit
2016-07-09 16:42:49 +08:00
bool alignmentCap = ( volumeHeader - > Attributes & EFI_FVB_ALIGNMENT_CAP ) ! = 0 ;
2015-03-13 14:48:53 +08:00
if ( ! alignmentCap ) {
2016-07-09 16:42:49 +08:00
if ( volumeHeader - > Attributes & 0xFFFF0000 )
2015-03-13 14:48:53 +08:00
msgAlignmentBitsSet = true ;
}
// Do not check for volume alignment on revision 1 volumes
2016-07-16 13:02:33 +08:00
// No one gives a single damn about setting it correctly
2015-03-13 14:48:53 +08:00
}
else if ( volumeHeader - > Revision = = 2 ) {
// Acquire alignment
2017-12-11 13:39:47 +08:00
alignment = ( UINT32 ) ( 1UL < < ( ( volumeHeader - > Attributes & EFI_FVB2_ALIGNMENT ) > > 16 ) ) ;
2015-03-13 14:48:53 +08:00
// Check alignment
2019-01-07 21:05:57 +08:00
if ( ! isUnknown & & ! model - > compressed ( parent ) & & ( ( model - > base ( parent ) + localOffset - imageBase ) % alignment ) )
2015-03-13 14:48:53 +08:00
msgUnaligned = true ;
}
2018-04-30 13:33:19 +08:00
else {
2015-03-13 14:48:53 +08:00
msgUnknownRevision = true ;
2018-04-30 13:33:19 +08:00
}
2015-03-13 14:48:53 +08:00
// Check attributes
// Determine value of empty byte
UINT8 emptyByte = volumeHeader - > Attributes & EFI_FVB_ERASE_POLARITY ? ' \xFF ' : ' \x00 ' ;
2017-10-12 13:59:23 +08:00
// Check for AppleCRC32 and UsedSpace in ZeroVector
2015-07-07 21:57:41 +08:00
bool hasAppleCrc32 = false ;
2015-03-13 14:48:53 +08:00
UINT32 volumeSize = volume . size ( ) ;
2015-07-07 21:57:41 +08:00
UINT32 appleCrc32 = * ( UINT32 * ) ( volume . constData ( ) + 8 ) ;
2017-10-12 13:59:23 +08:00
UINT32 usedSpace = * ( UINT32 * ) ( volume . constData ( ) + 12 ) ;
2015-07-07 21:57:41 +08:00
if ( appleCrc32 ! = 0 ) {
2015-03-13 14:48:53 +08:00
// Calculate CRC32 of the volume body
2019-07-25 01:30:59 +08:00
UINT32 crc = ( UINT32 ) crc32 ( 0 , ( const UINT8 * ) ( volume . constData ( ) + volumeHeader - > HeaderLength ) , volumeSize - volumeHeader - > HeaderLength ) ;
2015-07-07 21:57:41 +08:00
if ( crc = = appleCrc32 ) {
hasAppleCrc32 = true ;
2015-03-13 14:48:53 +08:00
}
}
// Check header checksum by recalculating it
bool msgInvalidChecksum = false ;
2016-06-26 11:54:21 +08:00
UByteArray tempHeader ( ( const char * ) volumeHeader , volumeHeader - > HeaderLength ) ;
2015-12-13 03:09:37 +08:00
( ( EFI_FIRMWARE_VOLUME_HEADER * ) tempHeader . data ( ) ) - > Checksum = 0 ;
UINT16 calculated = calculateChecksum16 ( ( const UINT16 * ) tempHeader . constData ( ) , volumeHeader - > HeaderLength ) ;
if ( volumeHeader - > Checksum ! = calculated )
2015-03-13 14:48:53 +08:00
msgInvalidChecksum = true ;
// Get info
2016-06-26 11:54:21 +08:00
UByteArray header = volume . left ( headerSize ) ;
UByteArray body = volume . mid ( headerSize ) ;
UString name = guidToUString ( volumeHeader - > FileSystemGuid ) ;
2016-12-23 06:34:24 +08:00
UString info = usprintf ( " ZeroVector: \n %02X %02X %02X %02X %02X %02X %02X %02X \n "
" %02X %02X %02X %02X %02X %02X %02X %02X \n Signature: _FVH \n FileSystem GUID: " ,
2016-06-26 11:54:21 +08:00
volumeHeader - > ZeroVector [ 0 ] , volumeHeader - > ZeroVector [ 1 ] , volumeHeader - > ZeroVector [ 2 ] , volumeHeader - > ZeroVector [ 3 ] ,
volumeHeader - > ZeroVector [ 4 ] , volumeHeader - > ZeroVector [ 5 ] , volumeHeader - > ZeroVector [ 6 ] , volumeHeader - > ZeroVector [ 7 ] ,
volumeHeader - > ZeroVector [ 8 ] , volumeHeader - > ZeroVector [ 9 ] , volumeHeader - > ZeroVector [ 10 ] , volumeHeader - > ZeroVector [ 11 ] ,
volumeHeader - > ZeroVector [ 12 ] , volumeHeader - > ZeroVector [ 13 ] , volumeHeader - > ZeroVector [ 14 ] , volumeHeader - > ZeroVector [ 15 ] )
2017-02-14 14:39:16 +08:00
+ guidToUString ( volumeHeader - > FileSystemGuid , false ) \
2016-06-26 16:05:45 +08:00
+ usprintf ( " \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Revision: %u \n Attributes: %08Xh \n Erase polarity: %u \n Checksum: %04Xh " ,
2016-06-26 11:54:21 +08:00
volumeSize , volumeSize ,
headerSize , headerSize ,
volumeSize - headerSize , volumeSize - headerSize ,
volumeHeader - > Revision ,
2016-06-26 16:05:45 +08:00
volumeHeader - > Attributes ,
( emptyByte ? 1 : 0 ) ,
2016-06-26 11:54:21 +08:00
volumeHeader - > Checksum ) +
2016-06-26 16:05:45 +08:00
( msgInvalidChecksum ? usprintf ( " , invalid, should be %04Xh " , calculated ) : UString ( " , valid " ) ) ;
2015-03-13 14:48:53 +08:00
// Extended header present
if ( volumeHeader - > Revision > 1 & & volumeHeader - > ExtHeaderOffset ) {
const EFI_FIRMWARE_VOLUME_EXT_HEADER * extendedHeader = ( const EFI_FIRMWARE_VOLUME_EXT_HEADER * ) ( volume . constData ( ) + volumeHeader - > ExtHeaderOffset ) ;
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n Extended header size: %Xh (%u) \n Volume GUID: " ,
2017-02-14 14:39:16 +08:00
extendedHeader - > ExtHeaderSize , extendedHeader - > ExtHeaderSize ) + guidToUString ( extendedHeader - > FvName , false ) ;
name = guidToUString ( extendedHeader - > FvName ) ; // Replace FFS GUID with volume GUID
2015-03-13 14:48:53 +08:00
}
// Add text
2016-06-26 11:54:21 +08:00
UString text ;
2015-07-07 21:57:41 +08:00
if ( hasAppleCrc32 )
2016-06-26 11:54:21 +08:00
text + = UString ( " AppleCRC32 " ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
UINT8 subtype = Subtypes : : UnknownVolume ;
if ( ! isUnknown ) {
if ( ffsVersion = = 2 )
subtype = Subtypes : : Ffs2Volume ;
else if ( ffsVersion = = 3 )
subtype = Subtypes : : Ffs3Volume ;
2016-04-07 14:23:37 +08:00
else if ( isNvramVolume )
subtype = Subtypes : : NvramVolume ;
2018-10-08 17:58:12 +08:00
else if ( isMicrocodeVolume )
subtype = Subtypes : : MicrocodeVolume ;
2015-03-13 14:48:53 +08:00
}
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Volume , subtype , name , text , info , header , body , UByteArray ( ) , Movable , parent ) ;
2016-10-28 00:31:15 +08:00
2016-12-04 06:36:01 +08:00
// Set parsing data for created volume
2016-10-28 00:31:15 +08:00
VOLUME_PARSING_DATA pdata ;
pdata . emptyByte = emptyByte ;
pdata . ffsVersion = ffsVersion ;
pdata . hasExtendedHeader = hasExtendedHeader ? TRUE : FALSE ;
pdata . extendedHeaderGuid = extendedHeaderGuid ;
pdata . alignment = alignment ;
pdata . revision = volumeHeader - > Revision ;
pdata . hasAppleCrc32 = hasAppleCrc32 ;
2017-10-12 13:59:23 +08:00
pdata . hasValidUsedSpace = FALSE ; // Will be updated later, if needed
pdata . usedSpace = usedSpace ;
2016-10-28 00:31:15 +08:00
pdata . isWeakAligned = ( volumeHeader - > Revision > 1 & & ( volumeHeader - > Attributes & EFI_FVB2_WEAK_ALIGNMENT ) ) ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2015-03-13 14:48:53 +08:00
// Show messages
if ( isUnknown )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: unknown file system " , __FUNCTION__ ) + guidToUString ( volumeHeader - > FileSystemGuid ) , index ) ;
2015-03-13 14:48:53 +08:00
if ( msgInvalidChecksum )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: volume header checksum is invalid " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
if ( msgAlignmentBitsSet )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: alignment bits set on volume without alignment capability " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
if ( msgUnaligned )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: unaligned volume " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
if ( msgUnknownRevision )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: unknown volume revision %u " , __FUNCTION__ , volumeHeader - > Revision ) , index ) ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2019-09-05 08:07:18 +08:00
BOOLEAN FfsParser : : microcodeHeaderValid ( const INTEL_MICROCODE_HEADER * ucodeHeader )
{
// Check main reserved bytes to be zero
bool reservedBytesValid = true ;
for ( UINT32 i = 0 ; i < sizeof ( ucodeHeader - > Reserved ) ; i + + ) {
if ( ucodeHeader - > Reserved [ i ] ! = 0x00 ) {
reservedBytesValid = false ;
break ;
}
}
if ( ! reservedBytesValid ) {
return FALSE ;
}
// Check CpuFlags reserved bytes to be zero
2019-09-07 04:16:26 +08:00
for ( UINT32 i = 0 ; i < sizeof ( ucodeHeader - > ProcessorFlagsReserved ) ; i + + ) {
if ( ucodeHeader - > ProcessorFlagsReserved [ i ] ! = 0x00 ) {
2019-09-05 08:07:18 +08:00
reservedBytesValid = false ;
break ;
}
}
if ( ! reservedBytesValid ) {
return FALSE ;
}
2019-09-06 03:25:47 +08:00
// Check data size to be multiple of 4 and less than 0x1000000
if ( ucodeHeader - > DataSize % 4 ! = 0 | |
ucodeHeader - > DataSize > 0xFFFFFF ) {
2019-09-05 08:07:18 +08:00
return FALSE ;
}
2019-09-06 03:58:51 +08:00
// Check TotalSize to be greater or equal than DataSize and less than 0x1000000
if ( ucodeHeader - > TotalSize < ucodeHeader - > DataSize | |
2019-09-06 03:25:47 +08:00
ucodeHeader - > TotalSize > 0xFFFFFF ) {
2019-09-05 08:07:18 +08:00
return FALSE ;
}
// Check date to be sane
// Check day to be in 0x01-0x09, 0x10-0x19, 0x20-0x29, 0x30-0x31
if ( ucodeHeader - > DateDay < 0x01 | |
( ucodeHeader - > DateDay > 0x09 & & ucodeHeader - > DateDay < 0x10 ) | |
( ucodeHeader - > DateDay > 0x19 & & ucodeHeader - > DateDay < 0x20 ) | |
( ucodeHeader - > DateDay > 0x29 & & ucodeHeader - > DateDay < 0x30 ) | |
ucodeHeader - > DateDay > 0x31 ) {
return FALSE ;
}
// Check month to be in 0x01-0x09, 0x10-0x12
if ( ucodeHeader - > DateMonth < 0x01 | |
( ucodeHeader - > DateMonth > 0x09 & & ucodeHeader - > DateMonth < 0x10 ) | |
ucodeHeader - > DateMonth > 0x12 ) {
return FALSE ;
}
// Check year to be in 0x1990-0x1999, 0x2000-0x2009, 0x2010-0x2019, 0x2020-0x2029, 0x2030-0x2030, 0x2040-0x2049
if ( ucodeHeader - > DateYear < 0x1990 | |
( ucodeHeader - > DateYear > 0x1999 & & ucodeHeader - > DateYear < 0x2000 ) | |
( ucodeHeader - > DateYear > 0x2009 & & ucodeHeader - > DateYear < 0x2010 ) | |
( ucodeHeader - > DateYear > 0x2019 & & ucodeHeader - > DateYear < 0x2020 ) | |
( ucodeHeader - > DateYear > 0x2029 & & ucodeHeader - > DateYear < 0x2030 ) | |
( ucodeHeader - > DateYear > 0x2039 & & ucodeHeader - > DateYear < 0x2040 ) | |
ucodeHeader - > DateYear > 0x2049 ) {
return FALSE ;
}
2019-09-07 04:16:26 +08:00
// Check HeaderVersion to be 1.
if ( ucodeHeader - > HeaderVersion ! = 1 ) {
2019-09-05 08:07:18 +08:00
return FALSE ;
}
2019-09-07 04:16:26 +08:00
// Check LoaderRevision to be 1.
if ( ucodeHeader - > LoaderRevision ! = 1 ) {
2019-09-06 04:38:53 +08:00
return FALSE ;
}
2019-09-05 08:07:18 +08:00
return TRUE ;
}
2018-10-08 17:58:12 +08:00
USTATUS FfsParser : : findNextRawAreaItem ( const UModelIndex & index , const UINT32 localOffset , UINT8 & nextItemType , UINT32 & nextItemOffset , UINT32 & nextItemSize , UINT32 & nextItemAlternativeSize )
2015-03-13 14:48:53 +08:00
{
2018-10-08 17:58:12 +08:00
UByteArray data = model - > body ( index ) ;
UINT32 dataSize = data . size ( ) ;
if ( dataSize < sizeof ( UINT32 ) )
return U_STORES_NOT_FOUND ;
UINT32 offset = localOffset ;
for ( ; offset < dataSize - sizeof ( UINT32 ) ; offset + + ) {
const UINT32 * currentPos = ( const UINT32 * ) ( data . constData ( ) + offset ) ;
const UINT32 restSize = dataSize - offset ;
2019-07-25 01:30:59 +08:00
if ( readUnaligned ( currentPos ) = = INTEL_MICROCODE_HEADER_VERSION_1 ) { // Intel microcode
2018-10-08 17:58:12 +08:00
// Check data size
2019-09-05 08:07:18 +08:00
if ( restSize < sizeof ( INTEL_MICROCODE_HEADER ) ) {
2019-07-25 01:30:59 +08:00
continue ;
}
2019-09-05 08:07:18 +08:00
// Check microcode header candidate
const INTEL_MICROCODE_HEADER * ucodeHeader = ( const INTEL_MICROCODE_HEADER * ) currentPos ;
if ( FALSE = = microcodeHeaderValid ( ucodeHeader ) ) {
2019-07-25 01:30:59 +08:00
continue ;
}
2018-10-08 17:58:12 +08:00
// All checks passed, microcode found
nextItemType = Types : : Microcode ;
nextItemSize = ucodeHeader - > TotalSize ;
nextItemAlternativeSize = ucodeHeader - > TotalSize ;
nextItemOffset = offset ;
break ;
}
2018-11-12 14:13:34 +08:00
else if ( readUnaligned ( currentPos ) = = EFI_FV_SIGNATURE ) {
2018-10-08 17:58:12 +08:00
if ( offset < EFI_FV_SIGNATURE_OFFSET )
continue ;
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
const EFI_FIRMWARE_VOLUME_HEADER * volumeHeader = ( const EFI_FIRMWARE_VOLUME_HEADER * ) ( data . constData ( ) + offset - EFI_FV_SIGNATURE_OFFSET ) ;
if ( volumeHeader - > FvLength < sizeof ( EFI_FIRMWARE_VOLUME_HEADER ) + 2 * sizeof ( EFI_FV_BLOCK_MAP_ENTRY ) | | volumeHeader - > FvLength > = 0xFFFFFFFFUL ) {
continue ;
}
if ( volumeHeader - > Revision ! = 1 & & volumeHeader - > Revision ! = 2 ) {
continue ;
}
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
// Calculate alternative volume size using it's BlockMap
nextItemAlternativeSize = 0 ;
const EFI_FV_BLOCK_MAP_ENTRY * entry = ( const EFI_FV_BLOCK_MAP_ENTRY * ) ( data . constData ( ) + offset - EFI_FV_SIGNATURE_OFFSET + sizeof ( EFI_FIRMWARE_VOLUME_HEADER ) ) ;
while ( entry - > NumBlocks ! = 0 & & entry - > Length ! = 0 ) {
if ( ( void * ) entry > = data . constData ( ) + data . size ( ) ) {
continue ;
}
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
nextItemAlternativeSize + = entry - > NumBlocks * entry - > Length ;
entry + = 1 ;
}
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
// All checks passed, volume found
nextItemType = Types : : Volume ;
nextItemSize = ( UINT32 ) volumeHeader - > FvLength ;
nextItemOffset = offset - EFI_FV_SIGNATURE_OFFSET ;
break ;
}
2019-08-20 02:36:02 +08:00
else if ( readUnaligned ( currentPos ) = = BPDT_GREEN_SIGNATURE | | readUnaligned ( currentPos ) = = BPDT_YELLOW_SIGNATURE ) {
// Check data size
if ( restSize < sizeof ( BPDT_HEADER ) )
continue ;
const BPDT_HEADER * bpdtHeader = ( const BPDT_HEADER * ) currentPos ;
// Check version
if ( bpdtHeader - > HeaderVersion ! = BPDT_HEADER_VERSION_1 ) // IFWI 2.0 only for now
continue ;
UINT32 ptBodySize = bpdtHeader - > NumEntries * sizeof ( BPDT_ENTRY ) ;
UINT32 ptSize = sizeof ( BPDT_HEADER ) + ptBodySize ;
// Check data size again
if ( restSize < ptSize )
continue ;
UINT32 sizeCandidate = 0 ;
// Parse partition table
const BPDT_ENTRY * firstPtEntry = ( const BPDT_ENTRY * ) ( ( const UINT8 * ) bpdtHeader + sizeof ( BPDT_HEADER ) ) ;
for ( UINT16 i = 0 ; i < bpdtHeader - > NumEntries ; i + + ) {
// Populate entry header
const BPDT_ENTRY * ptEntry = firstPtEntry + i ;
// Check that entry is present in the image
if ( ptEntry - > Offset ! = 0
& & ptEntry - > Offset ! = 0xFFFFFFFF
& & ptEntry - > Size ! = 0
& & sizeCandidate < ptEntry - > Offset + ptEntry - > Size ) {
sizeCandidate = ptEntry - > Offset + ptEntry - > Size ;
}
}
// Check size candidate
if ( sizeCandidate = = 0 )
continue ;
// All checks passed, BPDT found
nextItemType = Types : : BpdtStore ;
nextItemSize = sizeCandidate ;
nextItemAlternativeSize = sizeCandidate ;
nextItemOffset = offset ;
break ;
}
2018-10-08 17:58:12 +08:00
}
2015-12-12 17:59:38 +08:00
2018-10-08 17:58:12 +08:00
// No more stores found
if ( offset > = dataSize - sizeof ( UINT32 ) )
return U_STORES_NOT_FOUND ;
2015-12-12 17:59:38 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseVolumeNonUefiData ( const UByteArray & data , const UINT32 localOffset , const UModelIndex & index )
2015-09-19 16:08:26 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-09-19 16:08:26 +08:00
// Get info
2016-07-16 13:02:33 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , data . size ( ) , data . size ( ) ) ;
2015-09-19 16:08:26 +08:00
// Add padding tree item
2019-01-07 21:05:57 +08:00
UModelIndex paddingIndex = model - > addItem ( localOffset , Types : : Padding , Subtypes : : DataPadding , UString ( " Non-UEFI data " ) , UString ( ) , info , UByteArray ( ) , data , UByteArray ( ) , Fixed , index ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: non-UEFI data found in volume's free space " , __FUNCTION__ ) , paddingIndex ) ;
2015-09-19 16:08:26 +08:00
2016-07-16 13:02:33 +08:00
// Parse contents as RAW area
return parseRawArea ( paddingIndex ) ;
2015-09-19 16:08:26 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseVolumeBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
// Get volume header size and body
2016-06-26 11:54:21 +08:00
UByteArray volumeBody = model - > body ( index ) ;
2015-03-13 14:48:53 +08:00
UINT32 volumeHeaderSize = model - > header ( index ) . size ( ) ;
2016-03-28 21:03:32 +08:00
// Parse VSS NVRAM volumes with a dedicated function
2016-04-07 14:23:37 +08:00
if ( model - > subtype ( index ) = = Subtypes : : NvramVolume )
2017-12-11 09:56:00 +08:00
return nvramParser - > parseNvramVolumeBody ( index ) ;
2016-03-28 21:03:32 +08:00
2018-10-08 17:58:12 +08:00
// Parse Microcode volume with a dedicated function
if ( model - > subtype ( index ) = = Subtypes : : MicrocodeVolume )
return parseMicrocodeVolumeBody ( index ) ;
2016-10-28 00:31:15 +08:00
// Get required values from parsing data
UINT8 emptyByte = 0xFF ;
UINT8 ffsVersion = 2 ;
2017-10-12 13:59:23 +08:00
UINT32 usedSpace = 0 ;
2016-10-28 00:31:15 +08:00
if ( model - > hasEmptyParsingData ( index ) = = false ) {
UByteArray data = model - > parsingData ( index ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
emptyByte = pdata - > emptyByte ;
ffsVersion = pdata - > ffsVersion ;
2017-10-12 13:59:23 +08:00
usedSpace = pdata - > usedSpace ;
2016-10-28 00:31:15 +08:00
}
// Check for unknown FFS version
if ( ffsVersion ! = 2 & & ffsVersion ! = 3 )
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
// Search for and parse all files
UINT32 volumeBodySize = volumeBody . size ( ) ;
UINT32 fileOffset = 0 ;
while ( fileOffset < volumeBodySize ) {
2016-10-28 00:31:15 +08:00
UINT32 fileSize = getFileSize ( volumeBody , fileOffset , ffsVersion ) ;
2019-01-04 03:53:31 +08:00
// Check that we are at the empty space
2019-08-20 02:36:02 +08:00
UByteArray header = volumeBody . mid ( fileOffset , ( int ) std : : min ( sizeof ( EFI_FFS_FILE_HEADER ) , ( size_t ) volumeBodySize - fileOffset ) ) ;
2019-01-04 03:53:31 +08:00
if ( header . count ( emptyByte ) = = header . size ( ) ) { //Empty space
// Check volume usedSpace entry to be valid
if ( usedSpace > 0 & & usedSpace = = fileOffset + volumeHeaderSize ) {
if ( model - > hasEmptyParsingData ( index ) = = false ) {
UByteArray data = model - > parsingData ( index ) ;
VOLUME_PARSING_DATA * pdata = ( VOLUME_PARSING_DATA * ) data . data ( ) ;
pdata - > hasValidUsedSpace = TRUE ;
model - > setParsingData ( index , data ) ;
model - > setText ( index , model - > text ( index ) + " UsedSpace " ) ;
2017-10-12 13:59:23 +08:00
}
2019-01-04 03:53:31 +08:00
}
// Check free space to be actually free
UByteArray freeSpace = volumeBody . mid ( fileOffset ) ;
if ( freeSpace . count ( emptyByte ) ! = freeSpace . size ( ) ) {
// Search for the first non-empty byte
UINT32 i ;
UINT32 size = freeSpace . size ( ) ;
const UINT8 * current = ( UINT8 * ) freeSpace . constData ( ) ;
for ( i = 0 ; i < size ; i + + ) {
if ( * current + + ! = emptyByte )
break ;
2015-03-13 14:48:53 +08:00
}
2019-01-04 03:53:31 +08:00
// 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 ) {
UByteArray free = freeSpace . left ( i ) ;
2015-03-13 14:48:53 +08:00
// Get info
2019-01-04 03:53:31 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , free . size ( ) , free . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add free space item
2019-01-07 21:05:57 +08:00
model - > addItem ( volumeHeaderSize + fileOffset , Types : : FreeSpace , 0 , UString ( " Volume free space " ) , UString ( ) , info , UByteArray ( ) , free , UByteArray ( ) , Movable , index ) ;
2015-03-13 14:48:53 +08:00
}
2019-01-04 03:53:31 +08:00
// Parse non-UEFI data
parseVolumeNonUefiData ( freeSpace . mid ( i ) , volumeHeaderSize + fileOffset + i , index ) ;
2015-03-13 14:48:53 +08:00
}
2019-01-04 03:53:31 +08:00
else {
// Get info
UString info = usprintf ( " Full size: %Xh (%u) " , freeSpace . size ( ) , freeSpace . size ( ) ) ;
// Add free space item
2019-01-07 21:05:57 +08:00
model - > addItem ( volumeHeaderSize + fileOffset , Types : : FreeSpace , 0 , UString ( " Volume free space " ) , UString ( ) , info , UByteArray ( ) , freeSpace , UByteArray ( ) , Movable , index ) ;
2015-03-13 14:48:53 +08:00
}
2019-01-04 03:53:31 +08:00
break ; // Exit from parsing loop
2015-03-13 14:48:53 +08:00
}
2019-01-04 03:53:31 +08:00
// We aren't at the end of empty space
// Check that the remaining space can still have a file in it
if ( volumeBodySize - fileOffset < sizeof ( EFI_FFS_FILE_HEADER ) | | // Remaining space is smaller than the smallest possible file
volumeBodySize - fileOffset < fileSize ) { // Remaining space is smaller than non-empty file size
// Parse non-UEFI data
parseVolumeNonUefiData ( volumeBody . mid ( fileOffset ) , volumeHeaderSize + fileOffset , index ) ;
break ; // Exit from parsing loop
2015-03-13 14:48:53 +08:00
}
2018-04-30 13:33:19 +08:00
// Parse current file's header
2016-06-26 11:54:21 +08:00
UModelIndex fileIndex ;
2019-01-04 03:53:31 +08:00
USTATUS result = parseFileHeader ( volumeBody . mid ( fileOffset , fileSize ) , volumeHeaderSize + fileOffset , index , fileIndex ) ;
2018-04-30 13:33:19 +08:00
if ( result ) {
msg ( usprintf ( " %s: file header parsing failed with error " , __FUNCTION__ ) + errorCodeToUString ( result ) , index ) ;
}
2015-03-13 14:48:53 +08:00
// Move to next file
fileOffset + = fileSize ;
fileOffset = ALIGN8 ( fileOffset ) ;
}
// Check for duplicate GUIDs
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2016-06-26 11:54:21 +08:00
UModelIndex current = index . child ( i , 0 ) ;
2015-03-13 14:48:53 +08:00
// Skip non-file entries and pad files
if ( model - > type ( current ) ! = Types : : File | | model - > subtype ( current ) = = EFI_FV_FILETYPE_PAD )
continue ;
2016-04-21 04:41:18 +08:00
2016-10-28 00:31:15 +08:00
// Get current file GUID
UByteArray currentGuid ( model - > header ( current ) . constData ( ) , sizeof ( EFI_GUID ) ) ;
2016-04-21 04:41:18 +08:00
2015-12-12 17:59:38 +08:00
// Check files after current for having an equal GUID
2015-03-13 14:48:53 +08:00
for ( int j = i + 1 ; j < model - > rowCount ( index ) ; j + + ) {
2016-06-26 11:54:21 +08:00
UModelIndex another = index . child ( j , 0 ) ;
2016-04-21 04:41:18 +08:00
2015-03-13 14:48:53 +08:00
// Skip non-file entries
if ( model - > type ( another ) ! = Types : : File )
continue ;
2016-04-21 04:41:18 +08:00
2016-10-28 00:31:15 +08:00
// Get another file GUID
UByteArray anotherGuid ( model - > header ( another ) . constData ( ) , sizeof ( EFI_GUID ) ) ;
2016-04-21 04:41:18 +08:00
2015-12-12 17:59:38 +08:00
// Check GUIDs for being equal
2015-03-13 14:48:53 +08:00
if ( currentGuid = = anotherGuid ) {
2018-11-12 14:13:34 +08:00
msg ( usprintf ( " %s: file with duplicate GUID " , __FUNCTION__ ) + guidToUString ( readUnaligned ( ( EFI_GUID * ) ( anotherGuid . data ( ) ) ) ) , another ) ;
2015-03-13 14:48:53 +08:00
}
}
}
//Parse bodies
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2016-06-26 11:54:21 +08:00
UModelIndex current = index . child ( i , 0 ) ;
2015-03-13 14:48:53 +08:00
switch ( model - > type ( current ) ) {
case Types : : File :
parseFileBody ( current ) ;
break ;
case Types : : Padding :
case Types : : FreeSpace :
// No parsing required
break ;
default :
2016-06-26 11:54:21 +08:00
return U_UNKNOWN_ITEM_TYPE ;
2015-03-13 14:48:53 +08:00
}
}
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
UINT32 FfsParser : : getFileSize ( const UByteArray & volume , const UINT32 fileOffset , const UINT8 ffsVersion )
2015-03-13 14:48:53 +08:00
{
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) volume . size ( ) < fileOffset + sizeof ( EFI_FFS_FILE_HEADER ) ) {
return 0 ;
}
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) ( volume . constData ( ) + fileOffset ) ;
2015-03-13 14:48:53 +08:00
if ( ffsVersion = = 2 ) {
return uint24ToUint32 ( fileHeader - > Size ) ;
}
else if ( ffsVersion = = 3 ) {
2018-04-30 13:33:19 +08:00
if ( fileHeader - > Attributes & FFS_ATTRIB_LARGE_FILE ) {
if ( ( UINT32 ) volume . size ( ) < fileOffset + sizeof ( EFI_FFS_FILE_HEADER2 ) ) {
return 0 ;
}
const EFI_FFS_FILE_HEADER2 * fileHeader2 = ( const EFI_FFS_FILE_HEADER2 * ) ( volume . constData ( ) + fileOffset ) ;
return ( UINT32 ) fileHeader2 - > ExtendedSize ;
}
return uint24ToUint32 ( fileHeader - > Size ) ;
2015-03-13 14:48:53 +08:00
}
2018-04-30 13:33:19 +08:00
return 0 ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseFileHeader ( const UByteArray & file , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
2018-04-30 13:33:19 +08:00
if ( file . isEmpty ( ) ) {
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2018-04-30 13:33:19 +08:00
}
if ( ( UINT32 ) file . size ( ) < sizeof ( EFI_FFS_FILE_HEADER ) ) {
2016-06-26 11:54:21 +08:00
return U_INVALID_FILE ;
2018-04-30 13:33:19 +08:00
}
2015-12-12 17:59:38 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 ffsVersion = 2 ;
bool isWeakAligned = false ;
UINT32 volumeAlignment = 0xFFFFFFFF ;
UINT8 volumeRevision = 2 ;
2017-10-12 13:59:23 +08:00
UModelIndex parentVolumeIndex = model - > type ( parent ) = = Types : : Volume ? parent : model - > findParentOfType ( parent , Types : : Volume ) ;
2016-10-28 00:31:15 +08:00
if ( parentVolumeIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentVolumeIndex ) = = false ) {
UByteArray data = model - > parsingData ( parentVolumeIndex ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
ffsVersion = pdata - > ffsVersion ;
volumeAlignment = pdata - > alignment ;
volumeRevision = pdata - > revision ;
2018-05-08 23:42:16 +08:00
isWeakAligned = pdata - > isWeakAligned ;
2016-10-28 00:31:15 +08:00
}
2015-03-13 14:48:53 +08:00
// Get file header
2016-06-26 11:54:21 +08:00
UByteArray header = file . left ( sizeof ( EFI_FFS_FILE_HEADER ) ) ;
2017-12-11 09:56:00 +08:00
EFI_FFS_FILE_HEADER * tempFileHeader = ( EFI_FFS_FILE_HEADER * ) header . data ( ) ;
if ( ffsVersion = = 3 & & ( tempFileHeader - > Attributes & FFS_ATTRIB_LARGE_FILE ) ) {
2015-12-12 17:59:38 +08:00
if ( ( UINT32 ) file . size ( ) < sizeof ( EFI_FFS_FILE_HEADER2 ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_FILE ;
2015-03-13 14:48:53 +08:00
header = file . left ( sizeof ( EFI_FFS_FILE_HEADER2 ) ) ;
}
2017-12-11 09:56:00 +08:00
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) header . constData ( ) ;
2015-03-13 14:48:53 +08:00
// Check file alignment
bool msgUnalignedFile = false ;
UINT8 alignmentPower = ffsAlignmentTable [ ( fileHeader - > Attributes & FFS_ATTRIB_DATA_ALIGNMENT ) > > 3 ] ;
2017-12-11 09:56:00 +08:00
if ( volumeRevision > 1 & & ( fileHeader - > Attributes & FFS_ATTRIB_DATA_ALIGNMENT2 ) ) {
alignmentPower = ffsAlignment2Table [ ( fileHeader - > Attributes & FFS_ATTRIB_DATA_ALIGNMENT ) > > 3 ] ;
}
UINT32 alignment = ( UINT32 ) ( 1UL < < alignmentPower ) ;
2019-07-25 01:30:59 +08:00
if ( ( localOffset + header . size ( ) ) % alignment ) {
2015-03-13 14:48:53 +08:00
msgUnalignedFile = true ;
2019-07-25 01:30:59 +08:00
}
2015-03-13 14:48:53 +08:00
// Check file alignment agains volume alignment
2016-10-28 00:31:15 +08:00
bool msgFileAlignmentIsGreaterThanVolumeAlignment = false ;
2019-07-25 01:30:59 +08:00
if ( ! isWeakAligned & & volumeAlignment < alignment ) {
2016-10-28 00:31:15 +08:00
msgFileAlignmentIsGreaterThanVolumeAlignment = true ;
2019-07-25 01:30:59 +08:00
}
2017-12-11 09:56:00 +08:00
// Get file body
UByteArray body = file . mid ( header . size ( ) ) ;
// Check for file tail presence
UByteArray tail ;
bool msgInvalidTailValue = false ;
if ( volumeRevision = = 1 & & ( fileHeader - > Attributes & FFS_ATTRIB_TAIL_PRESENT ) ) {
//Check file tail;
UINT16 tailValue = * ( UINT16 * ) body . right ( sizeof ( UINT16 ) ) . constData ( ) ;
if ( fileHeader - > IntegrityCheck . TailReference ! = ( UINT16 ) ~ tailValue )
msgInvalidTailValue = true ;
// Get tail and remove it from file body
tail = body . right ( sizeof ( UINT16 ) ) ;
body = body . left ( body . size ( ) - sizeof ( UINT16 ) ) ;
}
2015-03-13 14:48:53 +08:00
// Check header checksum
2017-12-11 09:56:00 +08:00
UINT8 calculatedHeader = 0x100 - ( calculateSum8 ( ( const UINT8 * ) header . constData ( ) , header . size ( ) ) - fileHeader - > IntegrityCheck . Checksum . Header - fileHeader - > IntegrityCheck . Checksum . File - fileHeader - > State ) ;
2015-03-13 14:48:53 +08:00
bool msgInvalidHeaderChecksum = false ;
2019-07-25 01:30:59 +08:00
if ( fileHeader - > IntegrityCheck . Checksum . Header ! = calculatedHeader ) {
2015-03-13 14:48:53 +08:00
msgInvalidHeaderChecksum = true ;
2019-07-25 01:30:59 +08:00
}
2015-03-13 14:48:53 +08:00
// Check data checksum
// Data checksum must be calculated
bool msgInvalidDataChecksum = false ;
2015-12-13 03:09:37 +08:00
UINT8 calculatedData = 0 ;
2015-03-13 14:48:53 +08:00
if ( fileHeader - > Attributes & FFS_ATTRIB_CHECKSUM ) {
2017-12-11 09:56:00 +08:00
calculatedData = calculateChecksum8 ( ( const UINT8 * ) body . constData ( ) , body . size ( ) ) ;
2015-03-13 14:48:53 +08:00
}
// Data checksum must be one of predefined values
2017-12-11 09:56:00 +08:00
else if ( volumeRevision = = 1 ) {
2015-12-13 03:09:37 +08:00
calculatedData = FFS_FIXED_CHECKSUM ;
}
2017-12-11 09:56:00 +08:00
else {
2015-12-13 03:09:37 +08:00
calculatedData = FFS_FIXED_CHECKSUM2 ;
}
2015-03-13 14:48:53 +08:00
2019-07-25 01:30:59 +08:00
if ( fileHeader - > IntegrityCheck . Checksum . File ! = calculatedData ) {
2017-12-11 09:56:00 +08:00
msgInvalidDataChecksum = true ;
2019-07-25 01:30:59 +08:00
}
2015-03-13 14:48:53 +08:00
// Check file type
bool msgUnknownType = false ;
2016-10-28 00:31:15 +08:00
if ( fileHeader - > Type > EFI_FV_FILETYPE_MM_CORE_STANDALONE & & fileHeader - > Type ! = EFI_FV_FILETYPE_PAD ) {
2015-03-13 14:48:53 +08:00
msgUnknownType = true ;
} ;
// Get info
2016-06-26 11:54:21 +08:00
UString name ;
UString info ;
2018-04-30 13:33:19 +08:00
if ( fileHeader - > Type ! = EFI_FV_FILETYPE_PAD ) {
2016-06-26 11:54:21 +08:00
name = guidToUString ( fileHeader - > Name ) ;
2018-04-30 13:33:19 +08:00
} else {
2016-06-26 11:54:21 +08:00
name = UString ( " Pad-file " ) ;
2018-04-30 13:33:19 +08:00
}
2016-06-26 11:54:21 +08:00
2017-02-14 14:39:16 +08:00
info = UString ( " File GUID: " ) + guidToUString ( fileHeader - > Name , false ) +
2016-06-26 16:05:45 +08:00
usprintf ( " \n Type: %02Xh \n Attributes: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Tail size: %Xh (%u) \n State: %02Xh " ,
2016-06-26 11:54:21 +08:00
fileHeader - > Type ,
fileHeader - > Attributes ,
header . size ( ) + body . size ( ) + tail . size ( ) , header . size ( ) + body . size ( ) + tail . size ( ) ,
header . size ( ) , header . size ( ) ,
body . size ( ) , body . size ( ) ,
tail . size ( ) , tail . size ( ) ,
2016-06-26 16:05:45 +08:00
fileHeader - > State ) +
usprintf ( " \n Header checksum: %02Xh " , fileHeader - > IntegrityCheck . Checksum . Header ) + ( msgInvalidHeaderChecksum ? usprintf ( " , invalid, should be %02Xh " , calculatedHeader ) : UString ( " , valid " ) ) +
usprintf ( " \n Data checksum: %02Xh " , fileHeader - > IntegrityCheck . Checksum . File ) + ( msgInvalidDataChecksum ? usprintf ( " , invalid, should be %02Xh " , calculatedData ) : UString ( " , valid " ) ) ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
UString text ;
2015-06-20 02:26:45 +08:00
bool isVtf = false ;
2017-10-12 13:59:23 +08:00
bool isDxeCore = false ;
2016-03-21 06:59:03 +08:00
// Check if the file is a Volume Top File
2017-10-12 13:59:23 +08:00
UByteArray fileGuid = UByteArray ( ( const char * ) & fileHeader - > Name , sizeof ( EFI_GUID ) ) ;
if ( fileGuid = = EFI_FFS_VOLUME_TOP_FILE_GUID ) {
2015-06-20 02:26:45 +08:00
// Mark it as the last VTF
// This information will later be used to determine memory addresses of uncompressed image elements
// Because the last byte of the last VFT is mapped to 0xFFFFFFFF physical memory address
isVtf = true ;
2016-06-26 11:54:21 +08:00
text = UString ( " Volume Top File " ) ;
2015-06-20 02:26:45 +08:00
}
2017-10-12 13:59:23 +08:00
// Check if the file is the first DXE Core
2017-12-11 09:56:00 +08:00
else if ( fileGuid = = EFI_DXE_CORE_GUID | | fileGuid = = AMI_CORE_DXE_GUID ) {
// Mark is as first DXE core
// This information may be used to determine DXE volume offset for old AMI or post-IBB protected ranges
2017-10-12 13:59:23 +08:00
isDxeCore = true ;
}
2015-06-20 02:26:45 +08:00
2016-10-28 00:31:15 +08:00
// Construct fixed state
ItemFixedState fixed = ( ItemFixedState ) ( ( fileHeader - > Attributes & FFS_ATTRIB_FIXED ) ! = 0 ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : File , fileHeader - > Type , name , text , info , header , body , tail , fixed , parent ) ;
2016-10-28 00:31:15 +08:00
// Set parsing data for created file
FILE_PARSING_DATA pdata ;
pdata . emptyByte = ( fileHeader - > State & EFI_FILE_ERASE_POLARITY ) ? 0xFF : 0x00 ;
pdata . guid = fileHeader - > Name ;
2016-12-04 06:36:01 +08:00
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2016-10-28 00:31:15 +08:00
// Override lastVtf index, if needed
2015-06-20 02:26:45 +08:00
if ( isVtf ) {
lastVtf = index ;
}
2015-03-13 14:48:53 +08:00
2017-10-12 13:59:23 +08:00
// Override first DXE core index, if needed
if ( isDxeCore & & ! bgDxeCoreIndex . isValid ( ) ) {
bgDxeCoreIndex = index ;
}
2015-03-13 14:48:53 +08:00
// Show messages
if ( msgUnalignedFile )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: unaligned file " , __FUNCTION__ ) , index ) ;
2016-10-28 00:31:15 +08:00
if ( msgFileAlignmentIsGreaterThanVolumeAlignment )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: file alignment %Xh is greater than parent volume alignment %Xh " , __FUNCTION__ , alignment , volumeAlignment ) , index ) ;
2015-03-13 14:48:53 +08:00
if ( msgInvalidHeaderChecksum )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: invalid header checksum %02Xh, should be %02Xh " , __FUNCTION__ , fileHeader - > IntegrityCheck . Checksum . Header , calculatedHeader ) , index ) ;
if ( msgInvalidDataChecksum )
msg ( usprintf ( " %s: invalid data checksum %02Xh, should be %02Xh " , __FUNCTION__ , fileHeader - > IntegrityCheck . Checksum . File , calculatedData ) , index ) ;
if ( msgInvalidTailValue )
msg ( usprintf ( " %s: invalid tail value %04Xh " , __FUNCTION__ , * ( const UINT16 * ) tail . constData ( ) ) , index ) ;
2015-03-13 14:48:53 +08:00
if ( msgUnknownType )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: unknown file type %02Xh " , __FUNCTION__ , fileHeader - > Type ) , index ) ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
UINT32 FfsParser : : getSectionSize ( const UByteArray & file , const UINT32 sectionOffset , const UINT8 ffsVersion )
2015-03-13 14:48:53 +08:00
{
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) file . size ( ) < sectionOffset + sizeof ( EFI_COMMON_SECTION_HEADER ) ) {
return 0 ;
}
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( file . constData ( ) + sectionOffset ) ;
2015-03-13 14:48:53 +08:00
if ( ffsVersion = = 2 ) {
return uint24ToUint32 ( sectionHeader - > Size ) ;
}
else if ( ffsVersion = = 3 ) {
UINT32 size = uint24ToUint32 ( sectionHeader - > Size ) ;
2018-04-30 13:33:19 +08:00
if ( size = = EFI_SECTION2_IS_USED ) {
if ( ( UINT32 ) file . size ( ) < sectionOffset + sizeof ( EFI_COMMON_SECTION_HEADER2 ) ) {
return 0 ;
}
const EFI_COMMON_SECTION_HEADER2 * sectionHeader2 = ( const EFI_COMMON_SECTION_HEADER2 * ) ( file . constData ( ) + sectionOffset ) ;
return sectionHeader2 - > ExtendedSize ;
}
return size ;
2015-03-13 14:48:53 +08:00
}
2018-04-30 13:33:19 +08:00
return 0 ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseFileBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
// Do not parse non-file bodies
if ( model - > type ( index ) ! = Types : : File )
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
// Parse pad-file body
if ( model - > subtype ( index ) = = EFI_FV_FILETYPE_PAD )
return parsePadFileBody ( index ) ;
// Parse raw files as raw areas
2016-03-21 06:59:03 +08:00
if ( model - > subtype ( index ) = = EFI_FV_FILETYPE_RAW | | model - > subtype ( index ) = = EFI_FV_FILETYPE_ALL ) {
2017-10-12 13:59:23 +08:00
UByteArray fileGuid = UByteArray ( model - > header ( index ) . constData ( ) , sizeof ( EFI_GUID ) ) ;
2016-04-07 14:23:37 +08:00
// Parse NVAR store
2019-02-10 23:38:37 +08:00
if ( fileGuid = = NVRAM_NVAR_STORE_FILE_GUID ) {
model - > setText ( index , UString ( " NVAR store " ) ) ;
2017-12-11 09:56:00 +08:00
return nvramParser - > parseNvarStore ( index ) ;
2019-02-10 23:38:37 +08:00
}
2019-07-25 01:30:59 +08:00
else if ( fileGuid = = NVRAM_NVAR_PEI_EXTERNAL_DEFAULTS_FILE_GUID ) {
2019-02-10 23:38:37 +08:00
model - > setText ( index , UString ( " NVRAM external defaults " ) ) ;
return nvramParser - > parseNvarStore ( index ) ;
}
2019-07-25 01:30:59 +08:00
else if ( fileGuid = = NVRAM_NVAR_BB_DEFAULTS_FILE_GUID ) {
2019-04-12 00:30:30 +08:00
model - > setText ( index , UString ( " NVAR bb defaults " ) ) ;
return nvramParser - > parseNvarStore ( index ) ;
}
2017-10-12 13:59:23 +08:00
// Parse vendor hash file
2019-07-25 01:30:59 +08:00
else if ( fileGuid = = BG_VENDOR_HASH_FILE_GUID_PHOENIX ) {
2017-10-12 13:59:23 +08:00
return parseVendorHashFile ( fileGuid , index ) ;
2019-02-10 23:38:37 +08:00
}
2017-10-12 13:59:23 +08:00
2016-04-17 07:25:44 +08:00
return parseRawArea ( index ) ;
2016-03-21 06:59:03 +08:00
}
2015-03-13 14:48:53 +08:00
// Parse sections
2016-07-16 13:02:33 +08:00
return parseSections ( model - > body ( index ) , index , true ) ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parsePadFileBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
// Check if all bytes of the file are empty
2016-06-26 11:54:21 +08:00
UByteArray body = model - > body ( index ) ;
2016-10-28 00:31:15 +08:00
// Obtain required information from parent file
UINT8 emptyByte = 0xFF ;
UModelIndex parentFileIndex = model - > findParentOfType ( index , Types : : File ) ;
if ( parentFileIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentFileIndex ) = = false ) {
UByteArray data = model - > parsingData ( index ) ;
const FILE_PARSING_DATA * pdata = ( const FILE_PARSING_DATA * ) data . constData ( ) ;
emptyByte = pdata - > emptyByte ;
}
// Check if the while PAD file is empty
if ( body . size ( ) = = body . count ( emptyByte ) )
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
// Search for the first non-empty byte
2016-10-28 00:31:15 +08:00
UINT32 nonEmptyByteOffset ;
2015-03-13 14:48:53 +08:00
UINT32 size = body . size ( ) ;
const UINT8 * current = ( const UINT8 * ) body . constData ( ) ;
2016-10-28 00:31:15 +08:00
for ( nonEmptyByteOffset = 0 ; nonEmptyByteOffset < size ; nonEmptyByteOffset + + ) {
if ( * current + + ! = emptyByte )
2015-03-13 14:48:53 +08:00
break ;
}
// Add all bytes before as free space...
2019-01-07 21:05:57 +08:00
UINT32 headerSize = model - > header ( index ) . size ( ) ;
2016-10-28 00:31:15 +08:00
if ( nonEmptyByteOffset > = 8 ) {
2015-03-13 14:48:53 +08:00
// Align free space to 8 bytes boundary
2016-10-28 00:31:15 +08:00
if ( nonEmptyByteOffset ! = ALIGN8 ( nonEmptyByteOffset ) )
nonEmptyByteOffset = ALIGN8 ( nonEmptyByteOffset ) - 8 ;
2015-03-13 14:48:53 +08:00
2016-10-28 00:31:15 +08:00
UByteArray free = body . left ( nonEmptyByteOffset ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , free . size ( ) , free . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
model - > addItem ( headerSize , Types : : FreeSpace , 0 , UString ( " Free space " ) , UString ( ) , info , UByteArray ( ) , free , UByteArray ( ) , Movable , index ) ;
2016-10-28 00:31:15 +08:00
}
else {
nonEmptyByteOffset = 0 ;
2015-03-13 14:48:53 +08:00
}
// ... and all bytes after as a padding
2016-10-28 00:31:15 +08:00
UByteArray padding = body . mid ( nonEmptyByteOffset ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , padding . size ( ) , padding . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
UModelIndex dataIndex = model - > addItem ( headerSize + nonEmptyByteOffset , Types : : Padding , Subtypes : : DataPadding , UString ( " Non-UEFI data " ) , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
2015-03-13 14:48:53 +08:00
// Show message
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: non-UEFI data found in pad-file " , __FUNCTION__ ) , dataIndex ) ;
2015-03-13 14:48:53 +08:00
// Rename the file
2016-06-26 11:54:21 +08:00
model - > setName ( index , UString ( " Non-empty pad-file " ) ) ;
2015-03-13 14:48:53 +08:00
2018-10-08 17:58:12 +08:00
// Parse contents as RAW area
return parseRawArea ( dataIndex ) ;
2015-03-13 14:48:53 +08:00
}
2016-07-16 13:02:33 +08:00
USTATUS FfsParser : : parseSections ( const UByteArray & sections , const UModelIndex & index , const bool insertIntoTree )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
// Search for and parse all sections
UINT32 bodySize = sections . size ( ) ;
UINT32 headerSize = model - > header ( index ) . size ( ) ;
UINT32 sectionOffset = 0 ;
2016-06-26 11:54:21 +08:00
USTATUS result = U_SUCCESS ;
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 ffsVersion = 2 ;
UModelIndex parentVolumeIndex = model - > findParentOfType ( index , Types : : Volume ) ;
if ( parentVolumeIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentVolumeIndex ) = = false ) {
UByteArray data = model - > parsingData ( parentVolumeIndex ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
ffsVersion = pdata - > ffsVersion ;
}
2015-03-13 14:48:53 +08:00
while ( sectionOffset < bodySize ) {
// Get section size
2016-10-28 00:31:15 +08:00
UINT32 sectionSize = getSectionSize ( sections , sectionOffset , ffsVersion ) ;
2015-03-13 14:48:53 +08:00
// Check section size
if ( sectionSize < sizeof ( EFI_COMMON_SECTION_HEADER ) | | sectionSize > ( bodySize - sectionOffset ) ) {
2016-02-02 09:08:08 +08:00
// Final parsing
2016-07-16 13:02:33 +08:00
if ( insertIntoTree ) {
// Add padding to fill the rest of sections
UByteArray padding = sections . mid ( sectionOffset ) ;
2016-10-28 00:31:15 +08:00
2016-07-16 13:02:33 +08:00
// Get info
UString info = usprintf ( " Full size: %Xh (%u) " , padding . size ( ) , padding . size ( ) ) ;
2016-02-02 09:08:08 +08:00
// Add tree item
2019-01-07 21:05:57 +08:00
UModelIndex dataIndex = model - > addItem ( headerSize + sectionOffset , Types : : Padding , Subtypes : : DataPadding , UString ( " Non-UEFI data " ) , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
2015-03-13 14:48:53 +08:00
2016-02-02 09:08:08 +08:00
// Show message
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: non-UEFI data found in sections area " , __FUNCTION__ ) , dataIndex ) ;
2016-07-16 13:02:33 +08:00
// Exit from parsing loop
break ;
2016-02-02 09:08:08 +08:00
}
// Preparsing
2016-10-28 00:31:15 +08:00
else {
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-10-28 00:31:15 +08:00
}
2015-03-13 14:48:53 +08:00
}
// Parse section header
2016-06-26 11:54:21 +08:00
UModelIndex sectionIndex ;
2016-07-16 13:02:33 +08:00
result = parseSectionHeader ( sections . mid ( sectionOffset , sectionSize ) , headerSize + sectionOffset , index , sectionIndex , insertIntoTree ) ;
2016-02-02 09:08:08 +08:00
if ( result ) {
2016-07-16 13:02:33 +08:00
if ( insertIntoTree )
2016-06-26 11:54:21 +08:00
msg ( UString ( " parseSections: section header parsing failed with error " ) + errorCodeToUString ( result ) , index ) ;
2016-02-02 09:08:08 +08:00
else
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-02-02 09:08:08 +08:00
}
2018-01-23 16:00:03 +08:00
2015-03-13 14:48:53 +08:00
// Move to next section
sectionOffset + = sectionSize ;
sectionOffset = ALIGN4 ( sectionOffset ) ;
}
2016-07-16 13:02:33 +08:00
// Parse bodies, will be skipped if insertIntoTree is not required
2015-03-13 14:48:53 +08:00
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2016-06-26 11:54:21 +08:00
UModelIndex current = index . child ( i , 0 ) ;
2015-03-13 14:48:53 +08:00
switch ( model - > type ( current ) ) {
case Types : : Section :
parseSectionBody ( current ) ;
break ;
case Types : : Padding :
// No parsing required
break ;
default :
2016-06-26 11:54:21 +08:00
return U_UNKNOWN_ITEM_TYPE ;
2015-03-13 14:48:53 +08:00
}
}
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseSectionHeader ( const UByteArray & section , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index , const bool insertIntoTree )
2015-03-13 14:48:53 +08:00
{
2015-12-12 17:59:38 +08:00
// Check sanity
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER ) ) {
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2018-04-30 13:33:19 +08:00
}
2015-03-13 14:48:53 +08:00
2015-12-12 17:59:38 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
2015-03-13 14:48:53 +08:00
switch ( sectionHeader - > Type ) {
// Special
2016-10-28 00:31:15 +08:00
case EFI_SECTION_COMPRESSION : return parseCompressedSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
case EFI_SECTION_GUID_DEFINED : return parseGuidedSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
case EFI_SECTION_FREEFORM_SUBTYPE_GUID : return parseFreeformGuidedSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
case EFI_SECTION_VERSION : return parseVersionSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
2016-03-21 06:59:03 +08:00
case PHOENIX_SECTION_POSTCODE :
2016-10-28 00:31:15 +08:00
case INSYDE_SECTION_POSTCODE : return parsePostcodeSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
2015-03-13 14:48:53 +08:00
// Common
case EFI_SECTION_DISPOSABLE :
case EFI_SECTION_DXE_DEPEX :
case EFI_SECTION_PEI_DEPEX :
2016-10-28 00:31:15 +08:00
case EFI_SECTION_MM_DEPEX :
2015-03-13 14:48:53 +08:00
case EFI_SECTION_PE32 :
case EFI_SECTION_PIC :
2015-06-20 02:26:45 +08:00
case EFI_SECTION_TE :
2015-03-13 14:48:53 +08:00
case EFI_SECTION_COMPATIBILITY16 :
case EFI_SECTION_USER_INTERFACE :
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE :
2016-10-28 00:31:15 +08:00
case EFI_SECTION_RAW : return parseCommonSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
2015-12-12 17:59:38 +08:00
// Unknown
2015-03-13 14:48:53 +08:00
default :
2016-10-28 00:31:15 +08:00
USTATUS result = parseCommonSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: section with unknown type %02Xh " , __FUNCTION__ , sectionHeader - > Type ) , index ) ;
2015-03-13 14:48:53 +08:00
return result ;
}
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseCommonSectionHeader ( const UByteArray & section , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index , const bool insertIntoTree )
2015-03-13 14:48:53 +08:00
{
2015-12-12 17:59:38 +08:00
// Check sanity
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER ) ) {
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2018-04-30 13:33:19 +08:00
}
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 ffsVersion = 2 ;
2018-01-23 16:00:03 +08:00
UModelIndex parentVolumeIndex = model - > findParentOfType ( parent , Types : : Volume ) ;
2016-10-28 00:31:15 +08:00
if ( parentVolumeIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentVolumeIndex ) = = false ) {
UByteArray data = model - > parsingData ( parentVolumeIndex ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
ffsVersion = pdata - > ffsVersion ;
}
2015-03-13 14:48:53 +08:00
// Obtain header fields
2016-05-05 01:41:03 +08:00
UINT32 headerSize ;
UINT8 type ;
const EFI_COMMON_SECTION_HEADER_APPLE * appleHeader = ( const EFI_COMMON_SECTION_HEADER_APPLE * ) ( section . constData ( ) ) ;
if ( ( UINT32 ) section . size ( ) > = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) & & appleHeader - > Reserved = = EFI_SECTION_APPLE_USED ) {
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) ;
type = appleHeader - > Type ;
}
else {
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER ) ;
2016-10-28 00:31:15 +08:00
if ( ffsVersion = = 3 & & uint24ToUint32 ( sectionHeader - > Size ) = = EFI_SECTION2_IS_USED )
2016-05-05 01:41:03 +08:00
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER2 ) ;
type = sectionHeader - > Type ;
}
2015-03-13 14:48:53 +08:00
2016-05-05 01:41:03 +08:00
// Check sanity again
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) section . size ( ) < headerSize ) {
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2018-04-30 13:33:19 +08:00
}
2016-05-05 01:41:03 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( type ) + UString ( " section " ) ;
UString info = usprintf ( " Type: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) " ,
type ,
section . size ( ) , section . size ( ) ,
headerSize , headerSize ,
body . size ( ) , body . size ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2016-07-16 13:02:33 +08:00
if ( insertIntoTree ) {
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Section , type , name , UString ( ) , info , header , body , UByteArray ( ) , Movable , parent ) ;
2018-04-30 13:33:19 +08:00
}
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseCompressedSectionHeader ( const UByteArray & section , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index , const bool insertIntoTree )
2015-03-13 14:48:53 +08:00
{
2015-12-12 17:59:38 +08:00
// Check sanity
2016-05-05 01:41:03 +08:00
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-12-12 17:59:38 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 ffsVersion = 2 ;
2018-01-23 16:00:03 +08:00
UModelIndex parentVolumeIndex = model - > findParentOfType ( parent , Types : : Volume ) ;
2016-10-28 00:31:15 +08:00
if ( parentVolumeIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentVolumeIndex ) = = false ) {
UByteArray data = model - > parsingData ( parentVolumeIndex ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
ffsVersion = pdata - > ffsVersion ;
}
2015-03-13 14:48:53 +08:00
// Obtain header fields
2016-05-05 01:41:03 +08:00
UINT32 headerSize ;
UINT8 compressionType ;
UINT32 uncompressedLength ;
2015-03-13 14:48:53 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
2016-05-05 01:41:03 +08:00
const EFI_COMMON_SECTION_HEADER2 * section2Header = ( const EFI_COMMON_SECTION_HEADER2 * ) ( section . constData ( ) ) ;
const EFI_COMMON_SECTION_HEADER_APPLE * appleHeader = ( const EFI_COMMON_SECTION_HEADER_APPLE * ) ( section . constData ( ) ) ;
if ( ( UINT32 ) section . size ( ) > = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) & & appleHeader - > Reserved = = EFI_SECTION_APPLE_USED ) { // Check for apple section
const EFI_COMPRESSION_SECTION_APPLE * appleSectionHeader = ( const EFI_COMPRESSION_SECTION_APPLE * ) ( appleHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) + sizeof ( EFI_COMPRESSION_SECTION_APPLE ) ;
compressionType = ( UINT8 ) appleSectionHeader - > CompressionType ;
uncompressedLength = appleSectionHeader - > UncompressedLength ;
}
2016-10-28 00:31:15 +08:00
else if ( ffsVersion = = 3 & & uint24ToUint32 ( sectionHeader - > Size ) = = EFI_SECTION2_IS_USED ) { // Check for extended header section
2016-05-05 01:41:03 +08:00
const EFI_COMPRESSION_SECTION * compressedSectionHeader = ( const EFI_COMPRESSION_SECTION * ) ( section2Header + 1 ) ;
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER2 ) + sizeof ( EFI_COMPRESSION_SECTION ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-05-05 01:41:03 +08:00
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER2 ) + sizeof ( EFI_COMPRESSION_SECTION ) ;
compressionType = compressedSectionHeader - > CompressionType ;
uncompressedLength = compressedSectionHeader - > UncompressedLength ;
}
else { // Normal section
const EFI_COMPRESSION_SECTION * compressedSectionHeader = ( const EFI_COMPRESSION_SECTION * ) ( sectionHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER ) + sizeof ( EFI_COMPRESSION_SECTION ) ;
compressionType = compressedSectionHeader - > CompressionType ;
2015-03-13 14:48:53 +08:00
uncompressedLength = compressedSectionHeader - > UncompressedLength ;
}
2016-05-05 01:41:03 +08:00
// Check sanity again
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) section . size ( ) < headerSize ) {
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2018-04-30 13:33:19 +08:00
}
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( sectionHeader - > Type ) + UString ( " section " ) ;
UString info = usprintf ( " Type: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Compression type: %02Xh \n Decompressed size: %Xh (%u) " ,
sectionHeader - > Type ,
section . size ( ) , section . size ( ) ,
headerSize , headerSize ,
body . size ( ) , body . size ( ) ,
compressionType ,
uncompressedLength , uncompressedLength ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2016-07-16 13:02:33 +08:00
if ( insertIntoTree ) {
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Section , sectionHeader - > Type , name , UString ( ) , info , header , body , UByteArray ( ) , Movable , parent ) ;
2016-10-28 00:31:15 +08:00
// Set section parsing data
COMPRESSED_SECTION_PARSING_DATA pdata ;
pdata . compressionType = compressionType ;
pdata . uncompressedSize = uncompressedLength ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2016-02-09 19:00:14 +08:00
}
2018-04-30 13:33:19 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseGuidedSectionHeader ( const UByteArray & section , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index , const bool insertIntoTree )
2015-03-13 14:48:53 +08:00
{
2015-12-12 17:59:38 +08:00
// Check sanity
2016-05-05 01:41:03 +08:00
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-12-12 17:59:38 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 ffsVersion = 2 ;
2018-01-23 16:00:03 +08:00
UModelIndex parentVolumeIndex = model - > findParentOfType ( parent , Types : : Volume ) ;
2016-10-28 00:31:15 +08:00
if ( parentVolumeIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentVolumeIndex ) = = false ) {
UByteArray data = model - > parsingData ( parentVolumeIndex ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
ffsVersion = pdata - > ffsVersion ;
}
2015-03-13 14:48:53 +08:00
// Obtain header fields
2016-05-05 01:41:03 +08:00
UINT32 headerSize ;
EFI_GUID guid ;
UINT16 dataOffset ;
UINT16 attributes ;
2015-03-13 14:48:53 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
2016-05-05 01:41:03 +08:00
const EFI_COMMON_SECTION_HEADER2 * section2Header = ( const EFI_COMMON_SECTION_HEADER2 * ) ( section . constData ( ) ) ;
const EFI_COMMON_SECTION_HEADER_APPLE * appleHeader = ( const EFI_COMMON_SECTION_HEADER_APPLE * ) ( section . constData ( ) ) ;
if ( ( UINT32 ) section . size ( ) > = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) & & appleHeader - > Reserved = = EFI_SECTION_APPLE_USED ) { // Check for apple section
const EFI_GUID_DEFINED_SECTION_APPLE * appleSectionHeader = ( const EFI_GUID_DEFINED_SECTION_APPLE * ) ( appleHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) + sizeof ( EFI_GUID_DEFINED_SECTION_APPLE ) ;
if ( ( UINT32 ) section . size ( ) < headerSize )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-05-05 01:41:03 +08:00
guid = appleSectionHeader - > SectionDefinitionGuid ;
dataOffset = appleSectionHeader - > DataOffset ;
attributes = appleSectionHeader - > Attributes ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
else if ( ffsVersion = = 3 & & uint24ToUint32 ( sectionHeader - > Size ) = = EFI_SECTION2_IS_USED ) { // Check for extended header section
2016-05-05 01:41:03 +08:00
const EFI_GUID_DEFINED_SECTION * guidDefinedSectionHeader = ( const EFI_GUID_DEFINED_SECTION * ) ( section2Header + 1 ) ;
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER2 ) + sizeof ( EFI_GUID_DEFINED_SECTION ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-05-05 01:41:03 +08:00
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER2 ) + sizeof ( EFI_GUID_DEFINED_SECTION ) ;
guid = guidDefinedSectionHeader - > SectionDefinitionGuid ;
dataOffset = guidDefinedSectionHeader - > DataOffset ;
attributes = guidDefinedSectionHeader - > Attributes ;
}
else { // Normal section
const EFI_GUID_DEFINED_SECTION * guidDefinedSectionHeader = ( const EFI_GUID_DEFINED_SECTION * ) ( sectionHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER ) + sizeof ( EFI_GUID_DEFINED_SECTION ) ;
guid = guidDefinedSectionHeader - > SectionDefinitionGuid ;
dataOffset = guidDefinedSectionHeader - > DataOffset ;
attributes = guidDefinedSectionHeader - > Attributes ;
}
// Check sanity again
if ( ( UINT32 ) section . size ( ) < headerSize )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-02-09 19:00:14 +08:00
2015-12-12 17:59:38 +08:00
// Check for special GUIDed sections
2016-06-26 16:05:45 +08:00
UString additionalInfo ;
2016-06-26 11:54:21 +08:00
UByteArray baGuid ( ( const char * ) & guid , sizeof ( EFI_GUID ) ) ;
2016-02-09 19:00:14 +08:00
bool msgSignedSectionFound = false ;
2015-12-12 17:59:38 +08:00
bool msgNoAuthStatusAttribute = false ;
bool msgNoProcessingRequiredAttributeCompressed = false ;
bool msgNoProcessingRequiredAttributeSigned = false ;
bool msgInvalidCrc = false ;
bool msgUnknownCertType = false ;
bool msgUnknownCertSubtype = false ;
2018-11-11 21:33:13 +08:00
bool msgProcessingRequiredAttributeOnUnknownGuidedSection = false ;
2015-12-12 17:59:38 +08:00
if ( baGuid = = EFI_GUIDED_SECTION_CRC32 ) {
if ( ( attributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID ) = = 0 ) { // Check that AuthStatusValid attribute is set on compressed GUIDed sections
msgNoAuthStatusAttribute = true ;
}
2016-05-05 01:41:03 +08:00
if ( ( UINT32 ) section . size ( ) < headerSize + sizeof ( UINT32 ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-12-12 17:59:38 +08:00
2016-05-05 01:41:03 +08:00
UINT32 crc = * ( UINT32 * ) ( section . constData ( ) + headerSize ) ;
2016-06-26 11:54:21 +08:00
additionalInfo + = UString ( " \n Checksum type: CRC32 " ) ;
2015-12-12 17:59:38 +08:00
// Calculate CRC32 of section data
2019-07-25 01:30:59 +08:00
UINT32 calculated = ( UINT32 ) crc32 ( 0 , ( const UINT8 * ) section . constData ( ) + dataOffset , section . size ( ) - dataOffset ) ;
2015-12-12 17:59:38 +08:00
if ( crc = = calculated ) {
2016-06-26 11:54:21 +08:00
additionalInfo + = usprintf ( " \n Checksum: %08Xh, valid " , crc ) ;
2015-12-12 17:59:38 +08:00
}
else {
2016-06-26 16:05:45 +08:00
additionalInfo + = usprintf ( " \n Checksum: %08Xh, invalid, should be %08Xh " , crc , calculated ) ;
2015-12-12 17:59:38 +08:00
msgInvalidCrc = true ;
}
// No need to change dataOffset here
}
2018-11-11 21:33:13 +08:00
else if ( baGuid = = EFI_GUIDED_SECTION_LZMA | | baGuid = = EFI_GUIDED_SECTION_LZMAF86 | | baGuid = = EFI_GUIDED_SECTION_TIANO | | baGuid = = EFI_GUIDED_SECTION_GZIP ) {
2015-12-12 17:59:38 +08:00
if ( ( attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED ) = = 0 ) { // Check that ProcessingRequired attribute is set on compressed GUIDed sections
msgNoProcessingRequiredAttributeCompressed = true ;
}
// No need to change dataOffset here
}
2017-10-12 13:59:23 +08:00
else if ( baGuid = = EFI_CERT_TYPE_RSA2048_SHA256_GUID ) {
if ( ( attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED ) = = 0 ) { // Check that ProcessingRequired attribute is set on signed GUIDed sections
msgNoProcessingRequiredAttributeSigned = true ;
}
// Get certificate type and length
if ( ( UINT32 ) section . size ( ) < headerSize + sizeof ( EFI_CERT_BLOCK_RSA2048_SHA256 ) )
return U_INVALID_SECTION ;
// Adjust dataOffset
dataOffset + = sizeof ( EFI_CERT_BLOCK_RSA2048_SHA256 ) ;
additionalInfo + = UString ( " \n Certificate type: RSA2048/SHA256 " ) ;
msgSignedSectionFound = true ;
}
2015-12-12 17:59:38 +08:00
else if ( baGuid = = EFI_FIRMWARE_CONTENTS_SIGNED_GUID ) {
if ( ( attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED ) = = 0 ) { // Check that ProcessingRequired attribute is set on signed GUIDed sections
msgNoProcessingRequiredAttributeSigned = true ;
}
// Get certificate type and length
2016-05-05 01:41:03 +08:00
if ( ( UINT32 ) section . size ( ) < headerSize + sizeof ( WIN_CERTIFICATE ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-12-12 17:59:38 +08:00
2016-05-05 01:41:03 +08:00
const WIN_CERTIFICATE * winCertificate = ( const WIN_CERTIFICATE * ) ( section . constData ( ) + headerSize ) ;
2015-12-12 17:59:38 +08:00
UINT32 certLength = winCertificate - > Length ;
UINT16 certType = winCertificate - > CertificateType ;
// Adjust dataOffset
dataOffset + = certLength ;
// Check section size once again
if ( ( UINT32 ) section . size ( ) < dataOffset )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-12-12 17:59:38 +08:00
// Check certificate type
if ( certType = = WIN_CERT_TYPE_EFI_GUID ) {
2016-06-26 11:54:21 +08:00
additionalInfo + = UString ( " \n Certificate type: UEFI " ) ;
2015-12-12 17:59:38 +08:00
// Get certificate GUID
2016-05-05 01:41:03 +08:00
const WIN_CERTIFICATE_UEFI_GUID * winCertificateUefiGuid = ( const WIN_CERTIFICATE_UEFI_GUID * ) ( section . constData ( ) + headerSize ) ;
2016-06-26 11:54:21 +08:00
UByteArray certTypeGuid ( ( const char * ) & winCertificateUefiGuid - > CertType , sizeof ( EFI_GUID ) ) ;
2015-12-12 17:59:38 +08:00
if ( certTypeGuid = = EFI_CERT_TYPE_RSA2048_SHA256_GUID ) {
2016-06-26 11:54:21 +08:00
additionalInfo + = UString ( " \n Certificate subtype: RSA2048/SHA256 " ) ;
2015-12-12 17:59:38 +08:00
}
else {
2016-06-26 11:54:21 +08:00
additionalInfo + = UString ( " \n Certificate subtype: unknown, GUID " ) + guidToUString ( winCertificateUefiGuid - > CertType ) ;
2015-12-12 17:59:38 +08:00
msgUnknownCertSubtype = true ;
}
}
else {
2016-06-26 11:54:21 +08:00
additionalInfo + = usprintf ( " \n Certificate type: unknown (%04Xh) " , certType ) ;
2015-12-12 17:59:38 +08:00
msgUnknownCertType = true ;
}
2016-02-09 19:00:14 +08:00
msgSignedSectionFound = true ;
2015-12-12 17:59:38 +08:00
}
2018-11-11 21:33:13 +08:00
// Check that ProcessingRequired attribute is not set on GUIDed sections with unknown GUID
else if ( ( attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED ) = = EFI_GUIDED_SECTION_PROCESSING_REQUIRED ) {
msgProcessingRequiredAttributeOnUnknownGuidedSection = true ;
}
2015-12-12 17:59:38 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( dataOffset ) ;
UByteArray body = section . mid ( dataOffset ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = guidToUString ( guid ) ;
2017-02-14 14:39:16 +08:00
UString info = UString ( " Section GUID: " ) + guidToUString ( guid , false ) +
2016-06-26 11:54:21 +08:00
usprintf ( " \n Type: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Data offset: %Xh \n Attributes: %04Xh " ,
sectionHeader - > Type ,
section . size ( ) , section . size ( ) ,
header . size ( ) , header . size ( ) ,
body . size ( ) , body . size ( ) ,
dataOffset ,
attributes ) ;
2015-03-13 14:48:53 +08:00
2015-12-12 17:59:38 +08:00
// Append additional info
2016-06-26 16:05:45 +08:00
info + = additionalInfo ;
2015-12-12 17:59:38 +08:00
2015-03-13 14:48:53 +08:00
// Add tree item
2016-07-16 13:02:33 +08:00
if ( insertIntoTree ) {
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Section , sectionHeader - > Type , name , UString ( ) , info , header , body , UByteArray ( ) , Movable , parent ) ;
2016-10-28 00:31:15 +08:00
// Set parsing data
GUIDED_SECTION_PARSING_DATA pdata ;
pdata . guid = guid ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2016-02-09 19:00:14 +08:00
// Show messages
if ( msgSignedSectionFound )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: section signature may become invalid after any modification " , __FUNCTION__ ) , index ) ;
2016-02-09 19:00:14 +08:00
if ( msgNoAuthStatusAttribute )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: CRC32 GUIDed section without AuthStatusValid attribute " , __FUNCTION__ ) , index ) ;
2016-02-09 19:00:14 +08:00
if ( msgNoProcessingRequiredAttributeCompressed )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: compressed GUIDed section without ProcessingRequired attribute " , __FUNCTION__ ) , index ) ;
2016-02-09 19:00:14 +08:00
if ( msgNoProcessingRequiredAttributeSigned )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: signed GUIDed section without ProcessingRequired attribute " , __FUNCTION__ ) , index ) ;
2016-02-09 19:00:14 +08:00
if ( msgInvalidCrc )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: GUID defined section with invalid CRC32 " , __FUNCTION__ ) , index ) ;
2016-02-09 19:00:14 +08:00
if ( msgUnknownCertType )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: signed GUIDed section with unknown type " , __FUNCTION__ ) , index ) ;
2016-02-09 19:00:14 +08:00
if ( msgUnknownCertSubtype )
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: signed GUIDed section with unknown subtype " , __FUNCTION__ ) , index ) ;
2018-11-11 21:33:13 +08:00
if ( msgProcessingRequiredAttributeOnUnknownGuidedSection )
msg ( usprintf ( " %s: processing required bit set for GUIDed section with unknown GUID " , __FUNCTION__ ) , index ) ;
2016-02-09 19:00:14 +08:00
}
2015-12-12 17:59:38 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseFreeformGuidedSectionHeader ( const UByteArray & section , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index , const bool insertIntoTree )
2015-03-13 14:48:53 +08:00
{
2015-12-12 17:59:38 +08:00
// Check sanity
2016-05-05 01:41:03 +08:00
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-12-12 17:59:38 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 ffsVersion = 2 ;
2018-01-23 16:00:03 +08:00
UModelIndex parentVolumeIndex = model - > findParentOfType ( parent , Types : : Volume ) ;
2016-10-28 00:31:15 +08:00
if ( parentVolumeIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentVolumeIndex ) = = false ) {
UByteArray data = model - > parsingData ( parentVolumeIndex ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
ffsVersion = pdata - > ffsVersion ;
}
2015-03-13 14:48:53 +08:00
// Obtain header fields
2016-05-05 01:41:03 +08:00
UINT32 headerSize ;
EFI_GUID guid ;
UINT8 type ;
2015-03-13 14:48:53 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
2016-05-05 01:41:03 +08:00
const EFI_COMMON_SECTION_HEADER2 * section2Header = ( const EFI_COMMON_SECTION_HEADER2 * ) ( section . constData ( ) ) ;
const EFI_COMMON_SECTION_HEADER_APPLE * appleHeader = ( const EFI_COMMON_SECTION_HEADER_APPLE * ) ( section . constData ( ) ) ;
if ( ( UINT32 ) section . size ( ) > = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) & & appleHeader - > Reserved = = EFI_SECTION_APPLE_USED ) { // Check for apple section
const EFI_FREEFORM_SUBTYPE_GUID_SECTION * appleSectionHeader = ( const EFI_FREEFORM_SUBTYPE_GUID_SECTION * ) ( appleHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) + sizeof ( EFI_FREEFORM_SUBTYPE_GUID_SECTION ) ;
guid = appleSectionHeader - > SubTypeGuid ;
type = appleHeader - > Type ;
}
2016-10-28 00:31:15 +08:00
else if ( ffsVersion = = 3 & & uint24ToUint32 ( sectionHeader - > Size ) = = EFI_SECTION2_IS_USED ) { // Check for extended header section
2016-05-05 01:41:03 +08:00
const EFI_FREEFORM_SUBTYPE_GUID_SECTION * fsgSectionHeader = ( const EFI_FREEFORM_SUBTYPE_GUID_SECTION * ) ( section2Header + 1 ) ;
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER2 ) + sizeof ( EFI_FREEFORM_SUBTYPE_GUID_SECTION ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-05-05 01:41:03 +08:00
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER2 ) + sizeof ( EFI_FREEFORM_SUBTYPE_GUID_SECTION ) ;
guid = fsgSectionHeader - > SubTypeGuid ;
type = section2Header - > Type ;
}
else { // Normal section
const EFI_FREEFORM_SUBTYPE_GUID_SECTION * fsgSectionHeader = ( const EFI_FREEFORM_SUBTYPE_GUID_SECTION * ) ( sectionHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER ) + sizeof ( EFI_FREEFORM_SUBTYPE_GUID_SECTION ) ;
guid = fsgSectionHeader - > SubTypeGuid ;
type = sectionHeader - > Type ;
2015-03-13 14:48:53 +08:00
}
2016-05-05 01:41:03 +08:00
// Check sanity again
if ( ( UINT32 ) section . size ( ) < headerSize )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-05-05 01:41:03 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( type ) + ( " section " ) ;
UString info = usprintf ( " Type: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Subtype GUID: " ,
type ,
section . size ( ) , section . size ( ) ,
header . size ( ) , header . size ( ) ,
body . size ( ) , body . size ( ) )
2017-02-14 14:39:16 +08:00
+ guidToUString ( guid , false ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2016-07-16 13:02:33 +08:00
if ( insertIntoTree ) {
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Section , type , name , UString ( ) , info , header , body , UByteArray ( ) , Movable , parent ) ;
2016-10-28 00:31:15 +08:00
// Set parsing data
FREEFORM_GUIDED_SECTION_PARSING_DATA pdata ;
pdata . guid = guid ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2015-03-13 14:48:53 +08:00
2016-02-09 19:00:14 +08:00
// Rename section
2016-06-26 11:54:21 +08:00
model - > setName ( index , guidToUString ( guid ) ) ;
2016-02-09 19:00:14 +08:00
}
2018-04-30 13:33:19 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parseVersionSectionHeader ( const UByteArray & section , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index , const bool insertIntoTree )
2015-03-13 14:48:53 +08:00
{
2015-12-12 17:59:38 +08:00
// Check sanity
2016-05-05 01:41:03 +08:00
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-12-12 17:59:38 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 ffsVersion = 2 ;
2018-01-23 16:00:03 +08:00
UModelIndex parentVolumeIndex = model - > findParentOfType ( parent , Types : : Volume ) ;
2016-10-28 00:31:15 +08:00
if ( parentVolumeIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentVolumeIndex ) = = false ) {
UByteArray data = model - > parsingData ( parentVolumeIndex ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
ffsVersion = pdata - > ffsVersion ;
}
2015-03-13 14:48:53 +08:00
// Obtain header fields
2016-05-05 01:41:03 +08:00
UINT32 headerSize ;
UINT16 buildNumber ;
UINT8 type ;
2015-03-13 14:48:53 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
2016-05-05 01:41:03 +08:00
const EFI_COMMON_SECTION_HEADER2 * section2Header = ( const EFI_COMMON_SECTION_HEADER2 * ) ( section . constData ( ) ) ;
const EFI_COMMON_SECTION_HEADER_APPLE * appleHeader = ( const EFI_COMMON_SECTION_HEADER_APPLE * ) ( section . constData ( ) ) ;
if ( ( UINT32 ) section . size ( ) > = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) & & appleHeader - > Reserved = = EFI_SECTION_APPLE_USED ) { // Check for apple section
const EFI_VERSION_SECTION * versionHeader = ( const EFI_VERSION_SECTION * ) ( appleHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) + sizeof ( EFI_VERSION_SECTION ) ;
buildNumber = versionHeader - > BuildNumber ;
type = appleHeader - > Type ;
}
2016-10-28 00:31:15 +08:00
else if ( ffsVersion = = 3 & & uint24ToUint32 ( sectionHeader - > Size ) = = EFI_SECTION2_IS_USED ) { // Check for extended header section
2016-05-05 01:41:03 +08:00
const EFI_VERSION_SECTION * versionHeader = ( const EFI_VERSION_SECTION * ) ( section2Header + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER2 ) + sizeof ( EFI_VERSION_SECTION ) ;
buildNumber = versionHeader - > BuildNumber ;
type = section2Header - > Type ;
}
else { // Normal section
const EFI_VERSION_SECTION * versionHeader = ( const EFI_VERSION_SECTION * ) ( sectionHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER ) + sizeof ( EFI_VERSION_SECTION ) ;
buildNumber = versionHeader - > BuildNumber ;
type = sectionHeader - > Type ;
}
// Check sanity again
if ( ( UINT32 ) section . size ( ) < headerSize )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( type ) + ( " section " ) ;
2016-06-26 16:05:45 +08:00
UString info = usprintf ( " Type: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Build number: %u " ,
2016-06-26 11:54:21 +08:00
type ,
section . size ( ) , section . size ( ) ,
header . size ( ) , header . size ( ) ,
body . size ( ) , body . size ( ) ,
buildNumber ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2016-07-16 13:02:33 +08:00
if ( insertIntoTree ) {
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Section , type , name , UString ( ) , info , header , body , UByteArray ( ) , Movable , parent ) ;
2016-02-09 19:00:14 +08:00
}
2018-04-30 13:33:19 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-10-28 00:31:15 +08:00
USTATUS FfsParser : : parsePostcodeSectionHeader ( const UByteArray & section , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index , const bool insertIntoTree )
2015-03-13 14:48:53 +08:00
{
2015-12-12 17:59:38 +08:00
// Check sanity
2016-05-05 01:41:03 +08:00
if ( ( UINT32 ) section . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-12-12 17:59:38 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parent volume
UINT8 ffsVersion = 2 ;
2018-01-23 16:00:03 +08:00
UModelIndex parentVolumeIndex = model - > findParentOfType ( parent , Types : : Volume ) ;
2016-10-28 00:31:15 +08:00
if ( parentVolumeIndex . isValid ( ) & & model - > hasEmptyParsingData ( parentVolumeIndex ) = = false ) {
UByteArray data = model - > parsingData ( parentVolumeIndex ) ;
const VOLUME_PARSING_DATA * pdata = ( const VOLUME_PARSING_DATA * ) data . constData ( ) ;
ffsVersion = pdata - > ffsVersion ;
}
2015-03-13 14:48:53 +08:00
// Obtain header fields
2016-05-05 01:41:03 +08:00
UINT32 headerSize ;
UINT32 postCode ;
UINT8 type ;
2015-03-13 14:48:53 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
2016-05-05 01:41:03 +08:00
const EFI_COMMON_SECTION_HEADER2 * section2Header = ( const EFI_COMMON_SECTION_HEADER2 * ) ( section . constData ( ) ) ;
const EFI_COMMON_SECTION_HEADER_APPLE * appleHeader = ( const EFI_COMMON_SECTION_HEADER_APPLE * ) ( section . constData ( ) ) ;
if ( ( UINT32 ) section . size ( ) > = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) & & appleHeader - > Reserved = = EFI_SECTION_APPLE_USED ) { // Check for apple section
const POSTCODE_SECTION * postcodeHeader = ( const POSTCODE_SECTION * ) ( appleHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER_APPLE ) + sizeof ( POSTCODE_SECTION ) ;
postCode = postcodeHeader - > Postcode ;
type = appleHeader - > Type ;
}
2016-10-28 00:31:15 +08:00
else if ( ffsVersion = = 3 & & uint24ToUint32 ( sectionHeader - > Size ) = = EFI_SECTION2_IS_USED ) { // Check for extended header section
2016-05-05 01:41:03 +08:00
const POSTCODE_SECTION * postcodeHeader = ( const POSTCODE_SECTION * ) ( section2Header + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER2 ) + sizeof ( POSTCODE_SECTION ) ;
postCode = postcodeHeader - > Postcode ;
type = section2Header - > Type ;
}
else { // Normal section
const POSTCODE_SECTION * postcodeHeader = ( const POSTCODE_SECTION * ) ( sectionHeader + 1 ) ;
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER ) + sizeof ( POSTCODE_SECTION ) ;
postCode = postcodeHeader - > Postcode ;
type = sectionHeader - > Type ;
}
// Check sanity again
if ( ( UINT32 ) section . size ( ) < headerSize )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( type ) + ( " section " ) ;
2016-06-26 16:05:45 +08:00
UString info = usprintf ( " Type: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Postcode: %Xh " ,
type ,
2016-06-26 11:54:21 +08:00
section . size ( ) , section . size ( ) ,
header . size ( ) , header . size ( ) ,
body . size ( ) , body . size ( ) ,
postCode ) ;
2015-03-13 14:48:53 +08:00
// Add tree item
2016-07-16 13:02:33 +08:00
if ( insertIntoTree ) {
2019-01-07 21:05:57 +08:00
index = model - > addItem ( localOffset , Types : : Section , sectionHeader - > Type , name , UString ( ) , info , header , body , UByteArray ( ) , Movable , parent ) ;
2016-02-09 19:00:14 +08:00
}
2018-04-30 13:33:19 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
UByteArray header = model - > header ( index ) ;
2016-03-21 18:00:10 +08:00
if ( ( UINT32 ) header . size ( ) < sizeof ( EFI_COMMON_SECTION_HEADER ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2016-03-21 06:59:03 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( header . constData ( ) ) ;
2015-03-13 14:48:53 +08:00
switch ( sectionHeader - > Type ) {
// Encapsulation
case EFI_SECTION_COMPRESSION : return parseCompressedSectionBody ( index ) ;
case EFI_SECTION_GUID_DEFINED : return parseGuidedSectionBody ( index ) ;
2016-07-16 13:02:33 +08:00
case EFI_SECTION_DISPOSABLE : return parseSections ( model - > body ( index ) , index , true ) ;
2015-03-13 14:48:53 +08:00
// Leaf
2016-04-17 07:25:44 +08:00
case EFI_SECTION_FREEFORM_SUBTYPE_GUID : return parseRawArea ( index ) ;
2015-03-13 14:48:53 +08:00
case EFI_SECTION_VERSION : return parseVersionSectionBody ( index ) ;
case EFI_SECTION_DXE_DEPEX :
case EFI_SECTION_PEI_DEPEX :
2016-10-28 00:31:15 +08:00
case EFI_SECTION_MM_DEPEX : return parseDepexSectionBody ( index ) ;
2015-06-20 02:26:45 +08:00
case EFI_SECTION_TE : return parseTeImageSectionBody ( index ) ;
2015-03-13 14:48:53 +08:00
case EFI_SECTION_PE32 :
2015-06-20 02:26:45 +08:00
case EFI_SECTION_PIC : return parsePeImageSectionBody ( index ) ;
2015-03-13 14:48:53 +08:00
case EFI_SECTION_USER_INTERFACE : return parseUiSectionBody ( index ) ;
2016-04-17 07:25:44 +08:00
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE : return parseRawArea ( index ) ;
2015-03-13 14:48:53 +08:00
case EFI_SECTION_RAW : return parseRawSectionBody ( index ) ;
// No parsing needed
case EFI_SECTION_COMPATIBILITY16 :
2016-03-21 06:59:03 +08:00
case PHOENIX_SECTION_POSTCODE :
2015-03-13 14:48:53 +08:00
case INSYDE_SECTION_POSTCODE :
default :
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseCompressedSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parsing data
UINT8 compressionType = EFI_NOT_COMPRESSED ;
UINT32 uncompressedSize = model - > body ( index ) . size ( ) ;
if ( model - > hasEmptyParsingData ( index ) = = false ) {
UByteArray data = model - > parsingData ( index ) ;
const COMPRESSED_SECTION_PARSING_DATA * pdata = ( const COMPRESSED_SECTION_PARSING_DATA * ) data . constData ( ) ;
2018-11-12 14:13:34 +08:00
compressionType = readUnaligned ( pdata ) . compressionType ;
uncompressedSize = readUnaligned ( pdata ) . uncompressedSize ;
2016-10-28 00:31:15 +08:00
}
2015-03-13 14:48:53 +08:00
// Decompress section
2016-10-28 00:31:15 +08:00
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE ;
2019-01-04 03:53:31 +08:00
UINT32 dictionarySize = 0 ;
2016-06-26 11:54:21 +08:00
UByteArray decompressed ;
UByteArray efiDecompressed ;
2019-01-04 03:53:31 +08:00
USTATUS result = decompress ( model - > body ( index ) , compressionType , algorithm , dictionarySize , decompressed , efiDecompressed ) ;
2015-03-13 14:48:53 +08:00
if ( result ) {
2016-06-26 11:54:21 +08:00
msg ( UString ( " parseCompressedSectionBody: decompression failed with error " ) + errorCodeToUString ( result ) , index ) ;
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
// Check reported uncompressed size
2016-10-28 00:31:15 +08:00
if ( uncompressedSize ! = ( UINT32 ) decompressed . size ( ) ) {
2016-06-26 11:54:21 +08:00
msg ( usprintf ( " parseCompressedSectionBody: decompressed size stored in header %Xh (%u) differs from actual %Xh (%u) " ,
2016-10-28 00:31:15 +08:00
uncompressedSize , uncompressedSize ,
decompressed . size ( ) , decompressed . size ( ) ) ,
index ) ;
2016-06-26 11:54:21 +08:00
model - > addInfo ( index , usprintf ( " \n Actual decompressed size: %Xh (%u) " , decompressed . size ( ) , decompressed . size ( ) ) ) ;
2015-03-13 14:48:53 +08:00
}
2016-02-02 09:08:08 +08:00
// Check for undecided compression algorithm, this is a special case
if ( algorithm = = COMPRESSION_ALGORITHM_UNDECIDED ) {
// Try preparse of sections decompressed with Tiano algorithm
2016-07-16 13:02:33 +08:00
if ( U_SUCCESS = = parseSections ( decompressed , index , false ) ) {
2016-02-02 09:08:08 +08:00
algorithm = COMPRESSION_ALGORITHM_TIANO ;
}
// Try preparse of sections decompressed with EFI 1.1 algorithm
2016-07-16 13:02:33 +08:00
else if ( U_SUCCESS = = parseSections ( efiDecompressed , index , false ) ) {
2016-02-02 09:08:08 +08:00
algorithm = COMPRESSION_ALGORITHM_EFI11 ;
decompressed = efiDecompressed ;
}
else {
2016-06-26 11:54:21 +08:00
msg ( UString ( " parseCompressedSectionBody: can't guess the correct decompression algorithm, both preparse steps are failed " ) , index ) ;
2016-02-02 09:08:08 +08:00
}
}
2015-03-13 14:48:53 +08:00
// Add info
2016-06-26 11:54:21 +08:00
model - > addInfo ( index , UString ( " \n Compression algorithm: " ) + compressionTypeToUString ( algorithm ) ) ;
2019-01-04 03:53:31 +08:00
if ( algorithm = = COMPRESSION_ALGORITHM_LZMA | | algorithm = = COMPRESSION_ALGORITHM_IMLZMA ) {
model - > addInfo ( index , usprintf ( " \n LZMA dictionary size: %Xh " , dictionarySize ) ) ;
}
2015-03-13 14:48:53 +08:00
2016-10-28 00:31:15 +08:00
// Update parsing data
COMPRESSED_SECTION_PARSING_DATA pdata ;
pdata . algorithm = algorithm ;
2019-01-04 03:53:31 +08:00
pdata . dictionarySize = dictionarySize ;
2016-10-28 00:31:15 +08:00
pdata . compressionType = compressionType ;
pdata . uncompressedSize = uncompressedSize ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2015-12-30 06:39:43 +08:00
if ( algorithm ! = COMPRESSION_ALGORITHM_NONE )
model - > setCompressed ( index , true ) ;
2016-10-28 00:31:15 +08:00
2015-03-13 14:48:53 +08:00
// Parse decompressed data
2016-07-16 13:02:33 +08:00
return parseSections ( decompressed , index , true ) ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseGuidedSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parsing data
EFI_GUID guid = { 0 , 0 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 } } ;
if ( model - > hasEmptyParsingData ( index ) = = false ) {
UByteArray data = model - > parsingData ( index ) ;
const GUIDED_SECTION_PARSING_DATA * pdata = ( const GUIDED_SECTION_PARSING_DATA * ) data . constData ( ) ;
2018-11-12 14:13:34 +08:00
guid = readUnaligned ( pdata ) . guid ;
2016-10-28 00:31:15 +08:00
}
2015-03-13 14:48:53 +08:00
// Check if section requires processing
2016-06-26 11:54:21 +08:00
UByteArray processed = model - > body ( index ) ;
UByteArray efiDecompressed ;
UString info ;
2015-03-13 14:48:53 +08:00
bool parseCurrentSection = true ;
UINT8 algorithm = COMPRESSION_ALGORITHM_NONE ;
2019-01-04 03:53:31 +08:00
UINT32 dictionarySize = 0 ;
2016-10-10 14:05:04 +08:00
UByteArray baGuid = UByteArray ( ( const char * ) & guid , sizeof ( EFI_GUID ) ) ;
2015-12-12 17:59:38 +08:00
// Tiano compressed section
2016-10-10 14:05:04 +08:00
if ( baGuid = = EFI_GUIDED_SECTION_TIANO ) {
2019-01-04 03:53:31 +08:00
USTATUS result = decompress ( model - > body ( index ) , EFI_STANDARD_COMPRESSION , algorithm , dictionarySize , processed , efiDecompressed ) ;
2015-12-12 17:59:38 +08:00
if ( result ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: decompression failed with error " , __FUNCTION__ ) + errorCodeToUString ( result ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-02-02 09:08:08 +08:00
// Check for undecided compression algorithm, this is a special case
if ( algorithm = = COMPRESSION_ALGORITHM_UNDECIDED ) {
// Try preparse of sections decompressed with Tiano algorithm
2016-07-16 13:02:33 +08:00
if ( U_SUCCESS = = parseSections ( processed , index , false ) ) {
2016-02-02 09:08:08 +08:00
algorithm = COMPRESSION_ALGORITHM_TIANO ;
}
// Try preparse of sections decompressed with EFI 1.1 algorithm
2016-07-16 13:02:33 +08:00
else if ( U_SUCCESS = = parseSections ( efiDecompressed , index , false ) ) {
2016-02-02 09:08:08 +08:00
algorithm = COMPRESSION_ALGORITHM_EFI11 ;
processed = efiDecompressed ;
}
else {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: can't guess the correct decompression algorithm, both preparse steps are failed " , __FUNCTION__ ) , index ) ;
2018-05-08 23:42:16 +08:00
parseCurrentSection = false ;
2016-02-02 09:08:08 +08:00
}
2015-07-12 14:15:03 +08:00
}
2016-02-02 09:08:08 +08:00
2016-06-26 11:54:21 +08:00
info + = UString ( " \n Compression algorithm: " ) + compressionTypeToUString ( algorithm ) ;
2016-07-05 23:22:03 +08:00
info + = usprintf ( " \n Decompressed size: %Xh (%u) " , processed . size ( ) , processed . size ( ) ) ;
2015-12-12 17:59:38 +08:00
}
// LZMA compressed section
2016-10-10 14:05:04 +08:00
else if ( baGuid = = EFI_GUIDED_SECTION_LZMA | | baGuid = = EFI_GUIDED_SECTION_LZMAF86 ) {
2019-01-04 03:53:31 +08:00
USTATUS result = decompress ( model - > body ( index ) , EFI_CUSTOMIZED_COMPRESSION , algorithm , dictionarySize , processed , efiDecompressed ) ;
2015-12-12 17:59:38 +08:00
if ( result ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: decompression failed with error " , __FUNCTION__ ) + errorCodeToUString ( result ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2015-12-12 17:59:38 +08:00
if ( algorithm = = COMPRESSION_ALGORITHM_LZMA ) {
2016-06-26 11:54:21 +08:00
info + = UString ( " \n Compression algorithm: LZMA " ) ;
2016-07-05 23:22:03 +08:00
info + = usprintf ( " \n Decompressed size: %Xh (%u) " , processed . size ( ) , processed . size ( ) ) ;
2019-01-04 03:53:31 +08:00
info + = usprintf ( " \n LZMA dictionary size: %Xh " , dictionarySize ) ;
2015-03-13 14:48:53 +08:00
}
2016-04-18 22:44:49 +08:00
else {
2016-06-26 11:54:21 +08:00
info + = UString ( " \n Compression algorithm: unknown " ) ;
2018-05-08 23:42:16 +08:00
parseCurrentSection = false ;
}
2015-03-13 14:48:53 +08:00
}
2018-11-11 21:33:13 +08:00
// GZip compressed section
else if ( baGuid = = EFI_GUIDED_SECTION_GZIP ) {
USTATUS result = gzipDecompress ( model - > body ( index ) , processed ) ;
if ( result ) {
msg ( usprintf ( " %s: decompression failed with error " , __FUNCTION__ ) + errorCodeToUString ( result ) , index ) ;
return U_SUCCESS ;
}
info + = UString ( " \n Compression algorithm: GZip " ) ;
info + = usprintf ( " \n Decompressed size: %Xh (%u) " , processed . size ( ) , processed . size ( ) ) ;
}
2015-03-13 14:48:53 +08:00
// Add info
model - > addInfo ( index , info ) ;
2015-12-30 06:39:43 +08:00
// Update data
if ( algorithm ! = COMPRESSION_ALGORITHM_NONE )
model - > setCompressed ( index , true ) ;
2015-03-13 14:48:53 +08:00
2019-01-04 03:53:31 +08:00
// Set parsing data
GUIDED_SECTION_PARSING_DATA pdata ;
pdata . dictionarySize = dictionarySize ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2015-03-13 14:48:53 +08:00
if ( ! parseCurrentSection ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: GUID defined section can not be processed " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-07-16 13:02:33 +08:00
return parseSections ( processed , index , true ) ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseVersionSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
// Add info
2016-06-26 11:54:21 +08:00
model - > addInfo ( index , UString ( " \n Version string: " ) + UString : : fromUtf16 ( ( const CHAR16 * ) model - > body ( index ) . constData ( ) ) ) ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseDepexSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
UByteArray body = model - > body ( index ) ;
UString parsed ;
2015-03-13 14:48:53 +08:00
// Check data to be present
2015-12-12 17:59:38 +08:00
if ( body . size ( ) < 2 ) { // 2 is a minimal sane value, i.e TRUE + END
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: DEPEX section too short " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_DEPEX_PARSE_FAILED ;
2015-12-12 17:59:38 +08:00
}
2015-03-13 14:48:53 +08:00
const EFI_GUID * guid ;
const UINT8 * current = ( const UINT8 * ) body . constData ( ) ;
// Special cases of first opcode
switch ( * current ) {
case EFI_DEP_BEFORE :
if ( body . size ( ) ! = 2 * EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: DEPEX section too long for a section starting with BEFORE opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
guid = ( const EFI_GUID * ) ( current + EFI_DEP_OPCODE_SIZE ) ;
2018-11-12 14:13:34 +08:00
parsed + = UString ( " \n BEFORE " ) + guidToUString ( readUnaligned ( guid ) ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ;
if ( * current ! = EFI_DEP_END ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: DEPEX section ends with non-END opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
case EFI_DEP_AFTER :
if ( body . size ( ) ! = 2 * EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: DEPEX section too long for a section starting with AFTER opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
guid = ( const EFI_GUID * ) ( current + EFI_DEP_OPCODE_SIZE ) ;
2018-11-12 14:13:34 +08:00
parsed + = UString ( " \n AFTER " ) + guidToUString ( readUnaligned ( guid ) ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ;
if ( * current ! = EFI_DEP_END ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: DEPEX section ends with non-END opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
case EFI_DEP_SOR :
if ( body . size ( ) < = 2 * EFI_DEP_OPCODE_SIZE ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: DEPEX section too short for a section starting with SOR opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
parsed + = UString ( " \n SOR " ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE ;
break ;
}
// Parse the rest of depex
while ( current - ( const UINT8 * ) body . constData ( ) < body . size ( ) ) {
switch ( * current ) {
case EFI_DEP_BEFORE : {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: misplaced BEFORE opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
case EFI_DEP_AFTER : {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: misplaced AFTER opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
case EFI_DEP_SOR : {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: misplaced SOR opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
case EFI_DEP_PUSH :
// Check that the rest of depex has correct size
if ( ( UINT32 ) body . size ( ) - ( UINT32 ) ( current - ( const UINT8 * ) body . constData ( ) ) < = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ) {
parsed . clear ( ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: remains of DEPEX section too short for PUSH opcode " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
guid = ( const EFI_GUID * ) ( current + EFI_DEP_OPCODE_SIZE ) ;
2018-11-12 14:13:34 +08:00
parsed + = UString ( " \n PUSH " ) + guidToUString ( readUnaligned ( guid ) ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ;
break ;
case EFI_DEP_AND :
2016-06-26 11:54:21 +08:00
parsed + = UString ( " \n AND " ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_OR :
2016-06-26 11:54:21 +08:00
parsed + = UString ( " \n OR " ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_NOT :
2016-06-26 11:54:21 +08:00
parsed + = UString ( " \n NOT " ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_TRUE :
2016-06-26 11:54:21 +08:00
parsed + = UString ( " \n TRUE " ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_FALSE :
2016-06-26 11:54:21 +08:00
parsed + = UString ( " \n FALSE " ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_END :
2016-06-26 11:54:21 +08:00
parsed + = UString ( " \n END " ) ;
2015-03-13 14:48:53 +08:00
current + = EFI_DEP_OPCODE_SIZE ;
// Check that END is the last opcode
if ( current - ( const UINT8 * ) body . constData ( ) < body . size ( ) ) {
parsed . clear ( ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: DEPEX section ends with non-END opcode " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
}
break ;
default :
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: unknown opcode %02Xh " , __FUNCTION__ , * current ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
break ;
}
}
// Add info
2016-06-26 11:54:21 +08:00
model - > addInfo ( index , UString ( " \n Parsed expression: " ) + parsed ) ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseUiSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
UString text = UString : : fromUtf16 ( ( const CHAR16 * ) model - > body ( index ) . constData ( ) ) ;
2015-03-13 14:48:53 +08:00
// Add info
2016-06-26 11:54:21 +08:00
model - > addInfo ( index , UString ( " \n Text: " ) + text ) ;
2015-03-13 14:48:53 +08:00
// Rename parent file
model - > setText ( model - > findParentOfType ( index , Types : : File ) , text ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseAprioriRawSection ( const UByteArray & body , UString & parsed )
2015-04-02 16:04:37 +08:00
{
2015-12-12 17:59:38 +08:00
// Sanity check
if ( body . size ( ) % sizeof ( EFI_GUID ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: apriori file has size is not a multiple of 16 " , __FUNCTION__ ) ) ;
2015-12-12 17:59:38 +08:00
}
2015-04-02 16:04:37 +08:00
parsed . clear ( ) ;
UINT32 count = body . size ( ) / sizeof ( EFI_GUID ) ;
if ( count > 0 ) {
for ( UINT32 i = 0 ; i < count ; i + + ) {
const EFI_GUID * guid = ( const EFI_GUID * ) body . constData ( ) + i ;
2018-11-12 14:13:34 +08:00
parsed + = UString ( " \n " ) + guidToUString ( readUnaligned ( guid ) ) ;
2015-04-02 16:04:37 +08:00
}
}
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-04-02 16:04:37 +08:00
}
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseRawSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
// Check for apriori file
2016-06-26 11:54:21 +08:00
UModelIndex parentFile = model - > findParentOfType ( index , Types : : File ) ;
2016-10-28 00:31:15 +08:00
if ( ! parentFile . isValid ( ) )
return U_INVALID_FILE ; //TODO: better return code
2016-04-21 04:41:18 +08:00
// Get parent file parsing data
2016-10-28 00:31:15 +08:00
UByteArray parentFileGuid ( model - > header ( parentFile ) . constData ( ) , sizeof ( EFI_GUID ) ) ;
2015-03-13 14:48:53 +08:00
if ( parentFileGuid = = EFI_PEI_APRIORI_FILE_GUID ) { // PEI apriori file
2019-02-10 23:38:37 +08:00
// Set parent file text
model - > setText ( parentFile , UString ( " PEI apriori file " ) ) ;
2015-03-13 14:48:53 +08:00
// Parse apriori file list
2016-06-26 11:54:21 +08:00
UString str ;
USTATUS result = parseAprioriRawSection ( model - > body ( index ) , str ) ;
2015-03-13 14:48:53 +08:00
if ( ! result & & ! str . isEmpty ( ) )
2016-06-26 11:54:21 +08:00
model - > addInfo ( index , UString ( " \n File list: " ) + str ) ;
2019-02-10 23:38:37 +08:00
return result ;
2015-03-13 14:48:53 +08:00
}
else if ( parentFileGuid = = EFI_DXE_APRIORI_FILE_GUID ) { // DXE apriori file
2019-02-10 23:38:37 +08:00
// Rename parent file
model - > setText ( parentFile , UString ( " DXE apriori file " ) ) ;
2015-03-13 14:48:53 +08:00
// Parse apriori file list
2016-06-26 11:54:21 +08:00
UString str ;
USTATUS result = parseAprioriRawSection ( model - > body ( index ) , str ) ;
2015-03-13 14:48:53 +08:00
if ( ! result & & ! str . isEmpty ( ) )
2016-06-26 11:54:21 +08:00
model - > addInfo ( index , UString ( " \n File list: " ) + str ) ;
2019-02-10 23:38:37 +08:00
return result ;
2015-03-13 14:48:53 +08:00
}
2017-02-14 14:39:16 +08:00
else if ( parentFileGuid = = NVRAM_NVAR_EXTERNAL_DEFAULTS_FILE_GUID ) { // AMI NVRAM external defaults
2019-02-10 23:38:37 +08:00
// Rename parent file
2016-06-26 11:54:21 +08:00
model - > setText ( parentFile , UString ( " NVRAM external defaults " ) ) ;
2019-02-10 23:38:37 +08:00
// Parse NVAR area
return nvramParser - > parseNvarStore ( index ) ;
2016-04-21 04:41:18 +08:00
}
2017-10-12 13:59:23 +08:00
else if ( parentFileGuid = = BG_VENDOR_HASH_FILE_GUID_AMI ) { // AMI vendor hash file
// Parse AMI vendor hash file
2019-02-10 23:38:37 +08:00
return parseVendorHashFile ( parentFileGuid , index ) ;
2017-10-12 13:59:23 +08:00
}
2015-03-13 14:48:53 +08:00
// Parse as raw area
2016-04-17 07:25:44 +08:00
return parseRawArea ( index ) ;
2015-03-13 14:48:53 +08:00
}
2015-06-20 02:26:45 +08:00
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parsePeImageSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
2015-06-20 02:26:45 +08:00
// Sanity check
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2015-06-20 02:26:45 +08:00
// Get section body
2016-06-26 11:54:21 +08:00
UByteArray body = model - > body ( index ) ;
2015-12-12 17:59:38 +08:00
if ( ( UINT32 ) body . size ( ) < sizeof ( EFI_IMAGE_DOS_HEADER ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: section body size is smaller than DOS header size " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-12-12 17:59:38 +08:00
}
2015-03-13 14:48:53 +08:00
2016-06-26 16:05:45 +08:00
UString info ;
2015-03-13 14:48:53 +08:00
const EFI_IMAGE_DOS_HEADER * dosHeader = ( const EFI_IMAGE_DOS_HEADER * ) body . constData ( ) ;
if ( dosHeader - > e_magic ! = EFI_IMAGE_DOS_SIGNATURE ) {
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n DOS signature: %04Xh, invalid " , dosHeader - > e_magic ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: PE32 image with invalid DOS signature " , __FUNCTION__ ) , index ) ;
2015-12-12 17:59:38 +08:00
model - > addInfo ( index , info ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-12-12 17:59:38 +08:00
}
const EFI_IMAGE_PE_HEADER * peHeader = ( EFI_IMAGE_PE_HEADER * ) ( body . constData ( ) + dosHeader - > e_lfanew ) ;
if ( body . size ( ) < ( UINT8 * ) peHeader - ( UINT8 * ) dosHeader ) {
2016-06-26 11:54:21 +08:00
info + = UString ( " \n DOS header: invalid " ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: PE32 image with invalid DOS header " , __FUNCTION__ ) , index ) ;
2015-12-12 17:59:38 +08:00
model - > addInfo ( index , info ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-12-12 17:59:38 +08:00
}
if ( peHeader - > Signature ! = EFI_IMAGE_PE_SIGNATURE ) {
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n PE signature: %08Xh, invalid " , peHeader - > Signature ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: PE32 image with invalid PE signature " , __FUNCTION__ ) , index ) ;
2015-12-12 17:59:38 +08:00
model - > addInfo ( index , info ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-12-12 17:59:38 +08:00
}
const EFI_IMAGE_FILE_HEADER * imageFileHeader = ( const EFI_IMAGE_FILE_HEADER * ) ( peHeader + 1 ) ;
if ( body . size ( ) < ( UINT8 * ) imageFileHeader - ( UINT8 * ) dosHeader ) {
2016-06-26 11:54:21 +08:00
info + = UString ( " \n PE header: invalid " ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: PE32 image with invalid PE header " , __FUNCTION__ ) , index ) ;
2015-12-12 17:59:38 +08:00
model - > addInfo ( index , info ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-12-12 17:59:38 +08:00
}
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n DOS signature: %04Xh \n PE signature: %08Xh " ,
dosHeader - > e_magic ,
peHeader - > Signature ) +
2016-06-26 16:05:45 +08:00
UString ( " \n Machine type: " ) + machineTypeToUString ( imageFileHeader - > Machine ) +
2016-06-26 11:54:21 +08:00
usprintf ( " \n Number of sections: %u \n Characteristics: %04Xh " ,
imageFileHeader - > NumberOfSections ,
imageFileHeader - > Characteristics ) ;
2015-12-12 17:59:38 +08:00
EFI_IMAGE_OPTIONAL_HEADER_POINTERS_UNION optionalHeader ;
optionalHeader . H32 = ( const EFI_IMAGE_OPTIONAL_HEADER32 * ) ( imageFileHeader + 1 ) ;
if ( body . size ( ) < ( UINT8 * ) optionalHeader . H32 - ( UINT8 * ) dosHeader ) {
2016-06-26 11:54:21 +08:00
info + = UString ( " \n PE optional header: invalid " ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: PE32 image with invalid PE optional header " , __FUNCTION__ ) , index ) ;
2015-12-12 17:59:38 +08:00
model - > addInfo ( index , info ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-12-12 17:59:38 +08:00
}
if ( optionalHeader . H32 - > Magic = = EFI_IMAGE_PE_OPTIONAL_HDR32_MAGIC ) {
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n Optional header signature: %04Xh \n Subsystem: %04Xh \n Address of entry point: %Xh \n Base of code: %Xh \n Image base: %Xh " ,
optionalHeader . H32 - > Magic ,
optionalHeader . H32 - > Subsystem ,
optionalHeader . H32 - > AddressOfEntryPoint ,
optionalHeader . H32 - > BaseOfCode ,
optionalHeader . H32 - > ImageBase ) ;
2015-12-12 17:59:38 +08:00
}
else if ( optionalHeader . H32 - > Magic = = EFI_IMAGE_PE_OPTIONAL_HDR64_MAGIC ) {
2016-07-09 16:08:32 +08:00
info + = usprintf ( " \n Optional header signature: %04Xh \n Subsystem: %04Xh \n Address of entry point: %Xh \n Base of code: %Xh \n Image base: % " PRIX64 " h " ,
2016-06-26 11:54:21 +08:00
optionalHeader . H64 - > Magic ,
optionalHeader . H64 - > Subsystem ,
optionalHeader . H64 - > AddressOfEntryPoint ,
optionalHeader . H64 - > BaseOfCode ,
optionalHeader . H64 - > ImageBase ) ;
2015-03-13 14:48:53 +08:00
}
else {
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n Optional header signature: %04Xh, unknown " , optionalHeader . H32 - > Magic ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: PE32 image with invalid optional PE header signature " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
}
2015-06-20 02:26:45 +08:00
model - > addInfo ( index , info ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2015-06-20 02:26:45 +08:00
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : parseTeImageSectionBody ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
2015-12-12 17:59:38 +08:00
// Check sanity
2015-06-20 02:26:45 +08:00
if ( ! index . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2015-06-20 02:26:45 +08:00
// Get section body
2016-06-26 11:54:21 +08:00
UByteArray body = model - > body ( index ) ;
2015-12-12 17:59:38 +08:00
if ( ( UINT32 ) body . size ( ) < sizeof ( EFI_IMAGE_TE_HEADER ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: section body size is smaller than TE header size " , __FUNCTION__ ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-12-12 17:59:38 +08:00
}
2015-03-13 14:48:53 +08:00
2016-06-26 16:05:45 +08:00
UString info ;
2015-03-13 14:48:53 +08:00
const EFI_IMAGE_TE_HEADER * teHeader = ( const EFI_IMAGE_TE_HEADER * ) body . constData ( ) ;
if ( teHeader - > Signature ! = EFI_IMAGE_TE_SIGNATURE ) {
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n Signature: %04Xh, invalid " , teHeader - > Signature ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: TE image with invalid TE signature " , __FUNCTION__ ) , index ) ;
2015-03-13 14:48:53 +08:00
}
else {
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n Signature: %04Xh " , teHeader - > Signature ) +
2016-06-26 16:05:45 +08:00
UString ( " \n Machine type: " ) + machineTypeToUString ( teHeader - > Machine ) +
2016-06-26 11:54:21 +08:00
usprintf ( " \n Number of sections: %u \n Subsystem: %02Xh \n Stripped size: %Xh (%u) \n "
2016-07-09 16:08:32 +08:00
" Base of code: %Xh \n Address of entry point: %Xh \n Image base: % " PRIX64 " h \n Adjusted image base: % " PRIX64 " h " ,
2016-06-26 11:54:21 +08:00
teHeader - > NumberOfSections ,
2016-07-15 03:22:51 +08:00
teHeader - > Subsystem ,
2016-06-26 11:54:21 +08:00
teHeader - > StrippedSize , teHeader - > StrippedSize ,
teHeader - > BaseOfCode ,
teHeader - > AddressOfEntryPoint ,
teHeader - > ImageBase ,
teHeader - > ImageBase + teHeader - > StrippedSize - sizeof ( EFI_IMAGE_TE_HEADER ) ) ;
2015-03-13 14:48:53 +08:00
}
2015-06-20 02:26:45 +08:00
// Update parsing data
2016-10-28 00:31:15 +08:00
TE_IMAGE_SECTION_PARSING_DATA pdata ;
pdata . imageBaseType = EFI_IMAGE_TE_BASE_OTHER ; // Will be determined later
pdata . imageBase = ( UINT32 ) teHeader - > ImageBase ;
pdata . adjustedImageBase = ( UINT32 ) ( teHeader - > ImageBase + teHeader - > StrippedSize - sizeof ( EFI_IMAGE_TE_HEADER ) ) ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2015-06-20 02:26:45 +08:00
// Add TE info
model - > addInfo ( index , info ) ;
2015-03-13 14:48:53 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2015-06-20 02:26:45 +08:00
2016-06-26 11:54:21 +08:00
USTATUS FfsParser : : performSecondPass ( const UModelIndex & index )
2015-03-13 14:48:53 +08:00
{
2015-06-20 02:26:45 +08:00
// Sanity check
if ( ! index . isValid ( ) | | ! lastVtf . isValid ( ) )
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2015-03-13 14:48:53 +08:00
2015-12-30 06:39:43 +08:00
// Check for compressed lastVtf
if ( model - > compressed ( lastVtf ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: the last VTF appears inside compressed item, the image may be damaged " , __FUNCTION__ ) , lastVtf ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-06-20 02:26:45 +08:00
}
2016-07-15 03:22:51 +08:00
2015-06-20 02:26:45 +08:00
// Calculate address difference
2016-04-21 04:41:18 +08:00
const UINT32 vtfSize = model - > header ( lastVtf ) . size ( ) + model - > body ( lastVtf ) . size ( ) + model - > tail ( lastVtf ) . size ( ) ;
2019-01-07 21:05:57 +08:00
addressDiff = 0xFFFFFFFFULL - model - > base ( lastVtf ) - vtfSize + 1 ;
2015-03-13 14:48:53 +08:00
2019-07-25 01:30:59 +08:00
// Parse reset vector data
parseResetVectorData ( ) ;
2016-07-15 03:22:51 +08:00
// Find and parse FIT
2017-07-09 03:31:57 +08:00
parseFit ( index ) ;
2017-10-12 13:59:23 +08:00
// Check protected ranges
checkProtectedRanges ( index ) ;
2019-01-07 21:05:57 +08:00
// Check TE files to have original or adjusted base
checkTeImageBase ( index ) ;
2016-07-15 03:22:51 +08:00
return U_SUCCESS ;
}
2019-07-25 01:30:59 +08:00
USTATUS FfsParser : : parseResetVectorData ( )
{
// Sanity check
if ( ! lastVtf . isValid ( ) )
return U_SUCCESS ;
// Check VTF to have enough space at the end to fit Reset Vector Data
UByteArray vtf = model - > header ( lastVtf ) + model - > body ( lastVtf ) + model - > tail ( lastVtf ) ;
if ( ( UINT32 ) vtf . size ( ) < sizeof ( X86_RESET_VECTOR_DATA ) )
return U_SUCCESS ;
const X86_RESET_VECTOR_DATA * resetVectorData = ( const X86_RESET_VECTOR_DATA * ) ( vtf . constData ( ) + vtf . size ( ) - sizeof ( X86_RESET_VECTOR_DATA ) ) ;
// Add info
UString info = usprintf ( " \n AP entry vector: %02X %02X %02X %02X %02X %02X %02X %02X \n "
" Reset vector: %02X %02X %02X %02X %02X %02X %02X %02X \n "
" PEI core entry point: %08Xh \n "
" AP startup segment: %08X \n "
" BootFV base address: %08X \n " ,
resetVectorData - > ApEntryVector [ 0 ] , resetVectorData - > ApEntryVector [ 1 ] , resetVectorData - > ApEntryVector [ 2 ] , resetVectorData - > ApEntryVector [ 3 ] ,
resetVectorData - > ApEntryVector [ 4 ] , resetVectorData - > ApEntryVector [ 5 ] , resetVectorData - > ApEntryVector [ 6 ] , resetVectorData - > ApEntryVector [ 7 ] ,
resetVectorData - > ResetVector [ 0 ] , resetVectorData - > ResetVector [ 1 ] , resetVectorData - > ResetVector [ 2 ] , resetVectorData - > ResetVector [ 3 ] ,
resetVectorData - > ResetVector [ 4 ] , resetVectorData - > ResetVector [ 5 ] , resetVectorData - > ResetVector [ 6 ] , resetVectorData - > ResetVector [ 7 ] ,
resetVectorData - > PeiCoreEntryPoint ,
resetVectorData - > ApStartupSegment ,
resetVectorData - > BootFvBaseAddress ) ;
model - > addInfo ( lastVtf , info ) ;
return U_SUCCESS ;
}
2019-01-07 21:05:57 +08:00
USTATUS FfsParser : : checkTeImageBase ( const UModelIndex & index )
2017-10-12 13:59:23 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
return U_SUCCESS ;
2019-01-07 21:05:57 +08:00
// Determine relocation type of uncompressed TE image sections
if ( model - > compressed ( index ) = = false
& & model - > type ( index ) = = Types : : Section
& & model - > subtype ( index ) = = EFI_SECTION_TE ) {
// Obtain required values from parsing data
UINT32 originalImageBase = 0 ;
UINT32 adjustedImageBase = 0 ;
UINT8 imageBaseType = EFI_IMAGE_TE_BASE_OTHER ;
if ( model - > hasEmptyParsingData ( index ) = = false ) {
UByteArray data = model - > parsingData ( index ) ;
const TE_IMAGE_SECTION_PARSING_DATA * pdata = ( const TE_IMAGE_SECTION_PARSING_DATA * ) data . constData ( ) ;
originalImageBase = readUnaligned ( pdata ) . imageBase ;
adjustedImageBase = readUnaligned ( pdata ) . adjustedImageBase ;
}
if ( imageBase ! = 0 ) {
// Check data memory address to be equal to either ImageBase or AdjustedImageBase
UINT64 address = addressDiff + model - > base ( index ) ;
UINT32 base = ( UINT32 ) address + model - > header ( index ) . size ( ) ;
if ( imageBase = = base ) {
imageBaseType = EFI_IMAGE_TE_BASE_ORIGINAL ;
2017-10-12 13:59:23 +08:00
}
2019-01-07 21:05:57 +08:00
else if ( adjustedImageBase = = base ) {
imageBaseType = EFI_IMAGE_TE_BASE_ADJUSTED ;
2017-10-12 13:59:23 +08:00
}
2019-01-07 21:05:57 +08:00
else {
// Check for one-bit difference
UINT32 xored = base ^ imageBase ; // XOR result can't be zero
if ( ( xored & ( xored - 1 ) ) = = 0 ) { // Check that XOR result is a power of 2, i.e. has exactly one bit set
imageBaseType = EFI_IMAGE_TE_BASE_ORIGINAL ;
2017-10-12 13:59:23 +08:00
}
2019-01-07 21:05:57 +08:00
else { // The same check for adjustedImageBase
xored = base ^ adjustedImageBase ;
if ( ( xored & ( xored - 1 ) ) = = 0 ) {
2017-10-12 13:59:23 +08:00
imageBaseType = EFI_IMAGE_TE_BASE_ADJUSTED ;
}
}
}
2019-01-07 21:05:57 +08:00
// Show message if imageBaseType is still unknown
if ( imageBaseType = = EFI_IMAGE_TE_BASE_OTHER )
msg ( usprintf ( " %s: TE image base is neither zero, nor original, nor adjusted, nor top-swapped " , __FUNCTION__ ) , index ) ;
// Update parsing data
TE_IMAGE_SECTION_PARSING_DATA pdata ;
pdata . imageBaseType = imageBaseType ;
pdata . imageBase = originalImageBase ;
pdata . adjustedImageBase = adjustedImageBase ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2017-10-12 13:59:23 +08:00
}
}
// Process child items
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2019-01-07 21:05:57 +08:00
checkTeImageBase ( index . child ( i , 0 ) ) ;
2017-10-12 13:59:23 +08:00
}
return U_SUCCESS ;
}
2019-01-07 21:05:57 +08:00
USTATUS FfsParser : : addInfoRecursive ( const UModelIndex & index )
2017-10-12 13:59:23 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
return U_INVALID_PARAMETER ;
2019-01-07 21:05:57 +08:00
// Add offset
model - > addInfo ( index , usprintf ( " Offset: %Xh \n " , model - > offset ( index ) ) , false ) ;
// Add current base if the element is not compressed
2017-10-12 13:59:23 +08:00
// or it's compressed, but it's parent isn't
if ( ( ! model - > compressed ( index ) ) | | ( index . parent ( ) . isValid ( ) & & ! model - > compressed ( index . parent ( ) ) ) ) {
2019-01-07 21:05:57 +08:00
// Add physical address of the whole item or it's header and data portions separately
UINT64 address = addressDiff + model - > base ( index ) ;
if ( address < = 0xFFFFFFFFUL ) {
UINT32 headerSize = model - > header ( index ) . size ( ) ;
if ( headerSize ) {
model - > addInfo ( index , usprintf ( " Data address: %08Xh \n " , address + headerSize ) , false ) ;
model - > addInfo ( index , usprintf ( " Header address: %08Xh \n " , address ) , false ) ;
}
else {
model - > addInfo ( index , usprintf ( " Address: %08Xh \n " , address ) , false ) ;
}
}
// Add base
model - > addInfo ( index , usprintf ( " Base: %Xh \n " , model - > base ( index ) ) , false ) ;
2017-10-12 13:59:23 +08:00
}
2019-01-07 21:05:57 +08:00
model - > addInfo ( index , usprintf ( " Fixed: %s \n " , model - > fixed ( index ) ? " Yes " : " No " ) , false ) ;
2016-07-15 03:22:51 +08:00
// Process child items
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2019-01-07 21:05:57 +08:00
addInfoRecursive ( index . child ( i , 0 ) ) ;
2016-07-15 03:22:51 +08:00
}
return U_SUCCESS ;
}
2017-10-12 13:59:23 +08:00
USTATUS FfsParser : : checkProtectedRanges ( const UModelIndex & index )
{
// Sanity check
if ( ! index . isValid ( ) )
return U_INVALID_PARAMETER ;
// Calculate digest for BG-protected ranges
UByteArray protectedParts ;
bool bgProtectedRangeFound = false ;
for ( UINT32 i = 0 ; i < ( UINT32 ) bgProtectedRanges . size ( ) ; i + + ) {
2017-12-11 09:56:00 +08:00
if ( bgProtectedRanges [ i ] . Type = = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB ) {
2017-10-12 13:59:23 +08:00
bgProtectedRangeFound = true ;
2017-12-11 09:56:00 +08:00
bgProtectedRanges [ i ] . Offset - = ( UINT32 ) addressDiff ;
2017-10-12 13:59:23 +08:00
protectedParts + = openedImage . mid ( bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Size ) ;
markProtectedRangeRecursive ( index , bgProtectedRanges [ i ] ) ;
}
}
if ( bgProtectedRangeFound ) {
UByteArray digest ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
2017-12-11 09:56:00 +08:00
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
2017-10-12 13:59:23 +08:00
if ( digest ! = bgBpDigest ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: BG-protected ranges hash mismatch, opened image may refuse to boot " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
}
}
else if ( bgBootPolicyFound ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: BootPolicy doesn't define any BG-protected ranges " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
}
// Calculate digests for vendor-protected ranges
for ( UINT32 i = 0 ; i < ( UINT32 ) bgProtectedRanges . size ( ) ; i + + ) {
2017-12-11 09:56:00 +08:00
if ( bgProtectedRanges [ i ] . Type = = BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD
& & bgProtectedRanges [ i ] . Size ! = 0 & & bgProtectedRanges [ i ] . Size ! = 0xFFFFFFFF ) {
2017-10-12 13:59:23 +08:00
if ( ! bgDxeCoreIndex . isValid ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: can't determine DXE volume offset, old AMI protected range hash can't be checked " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
}
else {
// Offset will be determined as the offset of root volume with first DXE core
UModelIndex dxeRootVolumeIndex = model - > findLastParentOfType ( bgDxeCoreIndex , Types : : Volume ) ;
if ( ! dxeRootVolumeIndex . isValid ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: can't determine DXE volume offset, old AMI protected range hash can't be checked " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
}
else {
2019-01-07 21:05:57 +08:00
bgProtectedRanges [ i ] . Offset = model - > base ( dxeRootVolumeIndex ) ;
2017-10-12 13:59:23 +08:00
protectedParts = openedImage . mid ( bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Size ) ;
UByteArray digest ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
2017-12-11 09:56:00 +08:00
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
if ( digest ! = bgProtectedRanges [ i ] . Hash ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: old AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
2017-12-11 09:56:00 +08:00
bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Offset + bgProtectedRanges [ i ] . Size ) ,
2019-01-07 21:05:57 +08:00
model - > findByBase ( bgProtectedRanges [ i ] . Offset ) ) ;
2017-12-11 09:56:00 +08:00
}
markProtectedRangeRecursive ( index , bgProtectedRanges [ i ] ) ;
}
}
}
else if ( bgProtectedRanges [ i ] . Type = = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB ) {
if ( ! bgDxeCoreIndex . isValid ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: can't determine DXE volume offset, post-IBB protected range hash can't be checked " , __FUNCTION__ ) , index ) ;
2017-12-11 09:56:00 +08:00
}
else {
// Offset will be determined as the offset of root volume with first DXE core
UModelIndex dxeRootVolumeIndex = model - > findLastParentOfType ( bgDxeCoreIndex , Types : : Volume ) ;
if ( ! dxeRootVolumeIndex . isValid ( ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: can't determine DXE volume offset, post-IBB protected range hash can't be checked " , __FUNCTION__ ) , index ) ;
2017-12-11 09:56:00 +08:00
}
else
{
2019-01-07 21:05:57 +08:00
bgProtectedRanges [ i ] . Offset = model - > base ( dxeRootVolumeIndex ) ;
2017-12-11 09:56:00 +08:00
bgProtectedRanges [ i ] . Size = model - > header ( dxeRootVolumeIndex ) . size ( ) + model - > body ( dxeRootVolumeIndex ) . size ( ) + model - > tail ( dxeRootVolumeIndex ) . size ( ) ;
protectedParts = openedImage . mid ( bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Size ) ;
UByteArray digest ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
2017-10-12 13:59:23 +08:00
if ( digest ! = bgProtectedRanges [ i ] . Hash ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: post-IBB protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
2017-10-12 13:59:23 +08:00
bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Offset + bgProtectedRanges [ i ] . Size ) ,
2019-01-07 21:05:57 +08:00
model - > findByBase ( bgProtectedRanges [ i ] . Offset ) ) ;
2017-10-12 13:59:23 +08:00
}
markProtectedRangeRecursive ( index , bgProtectedRanges [ i ] ) ;
}
}
}
2017-12-11 09:56:00 +08:00
else if ( bgProtectedRanges [ i ] . Type = = BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW
& & bgProtectedRanges [ i ] . Size ! = 0 & & bgProtectedRanges [ i ] . Size ! = 0xFFFFFFFF
& & bgProtectedRanges [ i ] . Offset ! = 0 & & bgProtectedRanges [ i ] . Offset ! = 0xFFFFFFFF ) {
bgProtectedRanges [ i ] . Offset - = ( UINT32 ) addressDiff ;
2017-10-12 13:59:23 +08:00
protectedParts = openedImage . mid ( bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Size ) ;
UByteArray digest ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
2017-12-11 09:56:00 +08:00
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
2017-10-12 13:59:23 +08:00
if ( digest ! = bgProtectedRanges [ i ] . Hash ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
2017-10-12 13:59:23 +08:00
bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Offset + bgProtectedRanges [ i ] . Size ) ,
2019-01-07 21:05:57 +08:00
model - > findByBase ( bgProtectedRanges [ i ] . Offset ) ) ;
2017-10-12 13:59:23 +08:00
}
markProtectedRangeRecursive ( index , bgProtectedRanges [ i ] ) ;
}
2017-12-11 09:56:00 +08:00
else if ( bgProtectedRanges [ i ] . Type = = BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX
& & bgProtectedRanges [ i ] . Size ! = 0 & & bgProtectedRanges [ i ] . Size ! = 0xFFFFFFFF
& & bgProtectedRanges [ i ] . Offset ! = 0xFFFFFFFF ) {
2018-10-08 17:58:12 +08:00
bgProtectedRanges [ i ] . Offset + = ( UINT32 ) bgProtectedRegionsBase ;
2017-10-12 13:59:23 +08:00
protectedParts = openedImage . mid ( bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Size ) ;
UByteArray digest ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
2017-12-11 09:56:00 +08:00
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
2017-10-12 13:59:23 +08:00
if ( digest ! = bgProtectedRanges [ i ] . Hash ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: Phoenix protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
2017-10-12 13:59:23 +08:00
bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Offset + bgProtectedRanges [ i ] . Size ) ,
2019-01-07 21:05:57 +08:00
model - > findByBase ( bgProtectedRanges [ i ] . Offset ) ) ;
2017-10-12 13:59:23 +08:00
}
2017-11-06 15:10:06 +08:00
markProtectedRangeRecursive ( index , bgProtectedRanges [ i ] ) ;
}
2017-12-11 09:56:00 +08:00
else if ( bgProtectedRanges [ i ] . Type = = BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT
& & bgProtectedRanges [ i ] . Size ! = 0 & & bgProtectedRanges [ i ] . Size ! = 0xFFFFFFFF
& & bgProtectedRanges [ i ] . Offset ! = 0 & & bgProtectedRanges [ i ] . Offset ! = 0xFFFFFFFF ) {
bgProtectedRanges [ i ] . Offset - = ( UINT32 ) addressDiff ;
2017-11-06 15:10:06 +08:00
protectedParts = openedImage . mid ( bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Size ) ;
UByteArray digest ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
2017-12-11 09:56:00 +08:00
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
2017-11-06 15:10:06 +08:00
if ( digest ! = bgProtectedRanges [ i ] . Hash ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: Microsoft protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
2017-11-06 15:10:06 +08:00
bgProtectedRanges [ i ] . Offset , bgProtectedRanges [ i ] . Offset + bgProtectedRanges [ i ] . Size ) ,
2019-01-07 21:05:57 +08:00
model - > findByBase ( bgProtectedRanges [ i ] . Offset ) ) ;
2017-11-06 15:10:06 +08:00
}
2017-10-12 13:59:23 +08:00
markProtectedRangeRecursive ( index , bgProtectedRanges [ i ] ) ;
}
}
return U_SUCCESS ;
}
USTATUS FfsParser : : markProtectedRangeRecursive ( const UModelIndex & index , const BG_PROTECTED_RANGE & range )
{
if ( ! index . isValid ( ) )
return U_SUCCESS ;
// Mark compressed items
UModelIndex parentIndex = model - > parent ( index ) ;
if ( parentIndex . isValid ( ) & & model - > compressed ( index ) & & model - > compressed ( parentIndex ) ) {
model - > setMarking ( index , model - > marking ( parentIndex ) ) ;
}
// Mark normal items
else {
2019-01-07 21:05:57 +08:00
UINT32 currentOffset = model - > base ( index ) ;
2017-10-12 13:59:23 +08:00
UINT32 currentSize = model - > header ( index ) . size ( ) + model - > body ( index ) . size ( ) + model - > tail ( index ) . size ( ) ;
if ( std : : min ( currentOffset + currentSize , range . Offset + range . Size ) > std : : max ( currentOffset , range . Offset ) ) {
if ( range . Offset < = currentOffset & & currentOffset + currentSize < = range . Offset + range . Size ) { // Mark as fully in range
2019-08-20 02:36:02 +08:00
if ( range . Type = = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB ) {
model - > setMarking ( index , Qt : : red ) ;
}
else {
model - > setMarking ( index , Qt : : cyan ) ;
}
2017-10-12 13:59:23 +08:00
}
else { // Mark as partially in range
model - > setMarking ( index , Qt : : yellow ) ;
}
}
}
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
markProtectedRangeRecursive ( index . child ( i , 0 ) , range ) ;
}
return U_SUCCESS ;
}
USTATUS FfsParser : : parseVendorHashFile ( const UByteArray & fileGuid , const UModelIndex & index )
{
if ( ! index . isValid ( ) )
return EFI_INVALID_PARAMETER ;
if ( fileGuid = = BG_VENDOR_HASH_FILE_GUID_PHOENIX ) {
// File too small to have even a signature
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) model - > body ( index ) . size ( ) < sizeof ( BG_VENDOR_HASH_FILE_SIGNATURE_PHOENIX ) ) {
msg ( usprintf ( " %s: unknown or corrupted Phoenix hash file found " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
model - > setText ( index , UString ( " Phoenix hash file " ) ) ;
return U_INVALID_FILE ;
}
const BG_VENDOR_HASH_FILE_HEADER_PHOENIX * header = ( const BG_VENDOR_HASH_FILE_HEADER_PHOENIX * ) model - > body ( index ) . constData ( ) ;
if ( header - > Signature = = BG_VENDOR_HASH_FILE_SIGNATURE_PHOENIX ) {
if ( ( UINT32 ) model - > body ( index ) . size ( ) < sizeof ( BG_VENDOR_HASH_FILE_HEADER_PHOENIX ) | |
( UINT32 ) model - > body ( index ) . size ( ) < sizeof ( BG_VENDOR_HASH_FILE_HEADER_PHOENIX ) + header - > NumEntries * sizeof ( BG_VENDOR_HASH_FILE_ENTRY ) ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: unknown or corrupted Phoenix hash file found " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
model - > setText ( index , UString ( " Phoenix hash file " ) ) ;
return U_INVALID_FILE ;
}
if ( header - > NumEntries > 0 ) {
bool protectedRangesFound = false ;
for ( UINT32 i = 0 ; i < header - > NumEntries ; i + + ) {
protectedRangesFound = true ;
const BG_VENDOR_HASH_FILE_ENTRY * entry = ( const BG_VENDOR_HASH_FILE_ENTRY * ) ( header + 1 ) + i ;
2018-04-30 13:33:19 +08:00
2017-10-12 13:59:23 +08:00
BG_PROTECTED_RANGE range ;
range . Offset = entry - > Offset ;
range . Size = entry - > Size ;
range . Hash = UByteArray ( ( const char * ) entry - > Hash , sizeof ( entry - > Hash ) ) ;
range . Type = BG_PROTECTED_RANGE_VENDOR_HASH_PHOENIX ;
bgProtectedRanges . push_back ( range ) ;
}
if ( protectedRangesFound ) {
2019-01-07 21:05:57 +08:00
securityInfo + = usprintf ( " Phoenix hash file found at base %Xh \n Protected ranges: " , model - > base ( index ) ) ;
2017-10-12 13:59:23 +08:00
for ( UINT32 i = 0 ; i < header - > NumEntries ; i + + ) {
const BG_VENDOR_HASH_FILE_ENTRY * entry = ( const BG_VENDOR_HASH_FILE_ENTRY * ) ( header + 1 ) + i ;
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " \n RelativeOffset: %08Xh Size: %Xh \n Hash: " , entry - > Offset , entry - > Size ) ;
2018-05-08 23:42:16 +08:00
for ( UINT8 j = 0 ; j < sizeof ( entry - > Hash ) ; j + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " %02X " , entry - > Hash [ j ] ) ;
2017-10-12 13:59:23 +08:00
}
}
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n ------------------------------------------------------------------------ \n \n " ) ;
2017-10-12 13:59:23 +08:00
}
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: Phoenix hash file found " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
}
else {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: empty Phoenix hash file found " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
}
model - > setText ( index , UString ( " Phoenix hash file " ) ) ;
}
}
else if ( fileGuid = = BG_VENDOR_HASH_FILE_GUID_AMI ) {
UModelIndex fileIndex = model - > parent ( index ) ;
UINT32 size = model - > body ( index ) . size ( ) ;
2018-04-30 13:33:19 +08:00
if ( size ! = ( UINT32 ) model - > body ( index ) . count ( ' \xFF ' ) ) {
2017-10-12 13:59:23 +08:00
if ( size = = sizeof ( BG_VENDOR_HASH_FILE_HEADER_AMI_NEW ) ) {
bool protectedRangesFound = false ;
UINT32 NumEntries = ( UINT32 ) model - > body ( index ) . size ( ) / sizeof ( BG_VENDOR_HASH_FILE_ENTRY ) ;
for ( UINT32 i = 0 ; i < NumEntries ; i + + ) {
protectedRangesFound = true ;
const BG_VENDOR_HASH_FILE_ENTRY * entry = ( const BG_VENDOR_HASH_FILE_ENTRY * ) ( model - > body ( index ) . constData ( ) ) + i ;
BG_PROTECTED_RANGE range ;
range . Offset = entry - > Offset ;
range . Size = entry - > Size ;
range . Hash = UByteArray ( ( const char * ) entry - > Hash , sizeof ( entry - > Hash ) ) ;
range . Type = BG_PROTECTED_RANGE_VENDOR_HASH_AMI_NEW ;
bgProtectedRanges . push_back ( range ) ;
}
if ( protectedRangesFound ) {
2019-01-07 21:05:57 +08:00
securityInfo + = usprintf ( " New AMI hash file found at base %Xh \n Protected ranges: " , model - > base ( fileIndex ) ) ;
2017-10-12 13:59:23 +08:00
for ( UINT32 i = 0 ; i < NumEntries ; i + + ) {
const BG_VENDOR_HASH_FILE_ENTRY * entry = ( const BG_VENDOR_HASH_FILE_ENTRY * ) ( model - > body ( index ) . constData ( ) ) + i ;
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " \n Address: %08Xh Size: %Xh \n Hash: " , entry - > Offset , entry - > Size ) ;
2018-05-08 23:42:16 +08:00
for ( UINT8 j = 0 ; j < sizeof ( entry - > Hash ) ; j + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " %02X " , entry - > Hash [ j ] ) ;
2017-10-12 13:59:23 +08:00
}
}
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n ------------------------------------------------------------------------ \n \n " ) ;
2017-10-12 13:59:23 +08:00
}
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: new AMI hash file found " , __FUNCTION__ ) , fileIndex ) ;
2017-10-12 13:59:23 +08:00
}
else if ( size = = sizeof ( BG_VENDOR_HASH_FILE_HEADER_AMI_OLD ) ) {
2019-01-07 21:05:57 +08:00
securityInfo + = usprintf ( " Old AMI hash file found at base %Xh \n Protected range: " , model - > base ( fileIndex ) ) ;
2017-10-12 13:59:23 +08:00
const BG_VENDOR_HASH_FILE_HEADER_AMI_OLD * entry = ( const BG_VENDOR_HASH_FILE_HEADER_AMI_OLD * ) ( model - > body ( index ) . constData ( ) ) ;
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " \n Size: %Xh \n Hash: " , entry - > Size ) ;
2017-11-06 15:10:06 +08:00
for ( UINT8 i = 0 ; i < sizeof ( entry - > Hash ) ; i + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " %02X " , entry - > Hash [ i ] ) ;
2017-10-12 13:59:23 +08:00
}
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n ------------------------------------------------------------------------ \n \n " ) ;
2017-10-12 13:59:23 +08:00
BG_PROTECTED_RANGE range ;
range . Offset = 0 ;
range . Size = entry - > Size ;
range . Hash = UByteArray ( ( const char * ) entry - > Hash , sizeof ( entry - > Hash ) ) ;
range . Type = BG_PROTECTED_RANGE_VENDOR_HASH_AMI_OLD ;
bgProtectedRanges . push_back ( range ) ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: old AMI hash file found " , __FUNCTION__ ) , fileIndex ) ;
2017-10-12 13:59:23 +08:00
}
else {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: unknown or corrupted AMI hash file found " , __FUNCTION__ ) , index ) ;
2017-10-12 13:59:23 +08:00
}
}
else {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: empty AMI hash file found " , __FUNCTION__ ) , fileIndex ) ;
2017-10-12 13:59:23 +08:00
}
model - > setText ( fileIndex , UString ( " AMI hash file " ) ) ;
}
return U_SUCCESS ;
}
# ifndef U_ENABLE_FIT_PARSING_SUPPORT
USTATUS FfsParser : : parseFit ( const UModelIndex & index )
{
U_UNUSED_PARAMETER ( index ) ;
return U_SUCCESS ;
}
# else
2017-07-09 03:31:57 +08:00
USTATUS FfsParser : : parseFit ( const UModelIndex & index )
2016-07-15 03:22:51 +08:00
{
// Check sanity
if ( ! index . isValid ( ) )
return EFI_INVALID_PARAMETER ;
// Search for FIT
UModelIndex fitIndex ;
UINT32 fitOffset ;
2019-02-02 00:45:39 +08:00
findFitRecursive ( index , fitIndex , fitOffset ) ;
2016-07-15 03:22:51 +08:00
// FIT not found
if ( ! fitIndex . isValid ( ) )
return U_SUCCESS ;
2019-01-07 21:05:57 +08:00
// Explicitly set the item containing FIT as fixed
2016-07-15 03:22:51 +08:00
model - > setFixed ( fitIndex , true ) ;
// Special case of FIT header
UByteArray fitBody = model - > body ( fitIndex ) ;
const FIT_ENTRY * fitHeader = ( const FIT_ENTRY * ) ( fitBody . constData ( ) + fitOffset ) ;
// Check FIT checksum, if present
2017-10-12 13:59:23 +08:00
UINT32 fitSize = fitHeader - > Size * sizeof ( FIT_ENTRY ) ;
if ( fitHeader - > CsFlag ) {
2016-07-15 03:22:51 +08:00
// Calculate FIT entry checksum
UByteArray tempFIT = model - > body ( fitIndex ) . mid ( fitOffset , fitSize ) ;
FIT_ENTRY * tempFitHeader = ( FIT_ENTRY * ) tempFIT . data ( ) ;
2017-10-12 13:59:23 +08:00
tempFitHeader - > CsFlag = 0 ;
2016-07-15 03:22:51 +08:00
tempFitHeader - > Checksum = 0 ;
UINT8 calculated = calculateChecksum8 ( ( const UINT8 * ) tempFitHeader , fitSize ) ;
if ( calculated ! = fitHeader - > Checksum ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: invalid FIT table checksum %02Xh, should be %02Xh " , __FUNCTION__ , fitHeader - > Checksum , calculated ) , fitIndex ) ;
2016-07-15 03:22:51 +08:00
}
}
// Check fit header type
2017-10-12 13:59:23 +08:00
if ( fitHeader - > Type ! = FIT_TYPE_HEADER ) {
2016-12-23 06:34:24 +08:00
msg ( UString ( " Invalid FIT header type " ) , fitIndex ) ;
2017-10-12 13:59:23 +08:00
return U_INVALID_FIT ;
}
2016-07-18 12:49:31 +08:00
2016-11-03 03:40:38 +08:00
// Add FIT header
2016-07-15 03:22:51 +08:00
std : : vector < UString > currentStrings ;
2018-10-10 22:20:00 +08:00
currentStrings . push_back ( UString ( " _FIT_ " ) ) ;
2016-07-15 03:22:51 +08:00
currentStrings . push_back ( usprintf ( " %08Xh " , fitSize ) ) ;
currentStrings . push_back ( usprintf ( " %04Xh " , fitHeader - > Version ) ) ;
currentStrings . push_back ( usprintf ( " %02Xh " , fitHeader - > Checksum ) ) ;
currentStrings . push_back ( fitEntryTypeToUString ( fitHeader - > Type ) ) ;
2018-05-08 23:42:16 +08:00
currentStrings . push_back ( UString ( ) ) ; // Empty info for FIT header
2016-11-03 03:40:38 +08:00
fitTable . push_back ( std : : pair < std : : vector < UString > , UModelIndex > ( currentStrings , fitIndex ) ) ;
2016-07-15 03:22:51 +08:00
// Process all other entries
2017-10-12 13:59:23 +08:00
UModelIndex acmIndex ;
UModelIndex kmIndex ;
UModelIndex bpIndex ;
2016-07-15 03:22:51 +08:00
for ( UINT32 i = 1 ; i < fitHeader - > Size ; i + + ) {
currentStrings . clear ( ) ;
2016-12-23 06:34:24 +08:00
UString info ;
UModelIndex itemIndex ;
2016-07-15 03:22:51 +08:00
const FIT_ENTRY * currentEntry = fitHeader + i ;
2016-11-03 03:40:38 +08:00
UINT32 currentEntrySize = currentEntry - > Size ;
2016-07-15 03:22:51 +08:00
2017-10-12 13:59:23 +08:00
// Check sanity
if ( currentEntry - > Type = = FIT_TYPE_HEADER ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: second FIT header found, the table is damaged " , __FUNCTION__ ) , fitIndex ) ;
2017-10-12 13:59:23 +08:00
return U_INVALID_FIT ;
}
2018-10-08 17:58:12 +08:00
// Special case of version 0 entries
if ( currentEntry - > Version = = 0 ) {
const FIT_ENTRY_VERSION_0_CONFIG_POLICY * policy = ( const FIT_ENTRY_VERSION_0_CONFIG_POLICY * ) currentEntry ;
info + = usprintf ( " Index: %04Xh BitPosition: %02Xh AccessWidth: %02Xh DataRegAddr: %04Xh IndexRegAddr: %04Xh " ,
policy - > Index ,
policy - > BitPosition ,
policy - > AccessWidth ,
policy - > DataRegisterAddress ,
policy - > IndexRegisterAddress ) ;
}
else if ( currentEntry - > Address > addressDiff & & currentEntry - > Address < 0xFFFFFFFFUL ) { // Only elements in the image need to be parsed
2019-01-07 21:05:57 +08:00
UINT32 currentEntryBase = ( UINT32 ) ( currentEntry - > Address - addressDiff ) ;
itemIndex = model - > findByBase ( currentEntryBase ) ;
2017-10-12 13:59:23 +08:00
if ( itemIndex . isValid ( ) ) {
USTATUS status = U_INVALID_FIT ;
UByteArray item = model - > header ( itemIndex ) + model - > body ( itemIndex ) + model - > tail ( itemIndex ) ;
2019-01-07 21:05:57 +08:00
UINT32 localOffset = currentEntryBase - model - > base ( itemIndex ) ;
2017-10-12 13:59:23 +08:00
switch ( currentEntry - > Type ) {
case FIT_TYPE_MICROCODE :
2018-10-08 17:58:12 +08:00
status = parseFitEntryMicrocode ( item , localOffset , itemIndex , info , currentEntrySize ) ;
break ;
2017-10-12 13:59:23 +08:00
case FIT_TYPE_BIOS_AC_MODULE :
2018-10-08 17:58:12 +08:00
status = parseFitEntryAcm ( item , localOffset , itemIndex , info , currentEntrySize ) ;
2017-10-12 13:59:23 +08:00
acmIndex = itemIndex ;
break ;
case FIT_TYPE_AC_KEY_MANIFEST :
2018-10-08 17:58:12 +08:00
status = parseFitEntryBootGuardKeyManifest ( item , localOffset , itemIndex , info , currentEntrySize ) ;
2017-10-12 13:59:23 +08:00
kmIndex = itemIndex ;
break ;
case FIT_TYPE_AC_BOOT_POLICY :
2018-10-08 17:58:12 +08:00
status = parseFitEntryBootGuardBootPolicy ( item , localOffset , itemIndex , info , currentEntrySize ) ;
2017-10-12 13:59:23 +08:00
bpIndex = itemIndex ;
break ;
default :
// Do nothing
status = U_SUCCESS ;
break ;
2016-11-03 03:40:38 +08:00
}
2016-12-23 06:34:24 +08:00
2017-10-12 13:59:23 +08:00
if ( status ! = U_SUCCESS )
itemIndex = UModelIndex ( ) ;
}
2018-04-30 13:33:19 +08:00
else {
msg ( usprintf ( " %s: FIT entry #%d not found in the image " , __FUNCTION__ , i ) , fitIndex ) ;
}
2016-07-15 03:22:51 +08:00
}
2019-01-07 21:05:57 +08:00
if ( itemIndex . isValid ( ) ) {
// Explicitly set the item referenced by FIT as fixed
// TODO: lift this restriction after FIT builder is ready
model - > setFixed ( itemIndex , true ) ;
}
2016-07-15 03:22:51 +08:00
// Add entry to fitTable
2018-10-08 17:58:12 +08:00
currentStrings . push_back ( usprintf ( " %016 " PRIX64 " h " , currentEntry - > Address ) ) ;
2016-11-03 03:40:38 +08:00
currentStrings . push_back ( usprintf ( " %08Xh " , currentEntrySize , currentEntrySize ) ) ;
2016-07-15 03:22:51 +08:00
currentStrings . push_back ( usprintf ( " %04Xh " , currentEntry - > Version ) ) ;
currentStrings . push_back ( usprintf ( " %02Xh " , currentEntry - > Checksum ) ) ;
currentStrings . push_back ( fitEntryTypeToUString ( currentEntry - > Type ) ) ;
2016-11-03 03:40:38 +08:00
currentStrings . push_back ( info ) ;
fitTable . push_back ( std : : pair < std : : vector < UString > , UModelIndex > ( currentStrings , itemIndex ) ) ;
2016-07-15 03:22:51 +08:00
}
2017-10-12 13:59:23 +08:00
// Perform validation of BootGuard stuff
if ( bgAcmFound ) {
if ( ! bgKeyManifestFound ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: ACM found, but KeyManifest isn't " , __FUNCTION__ ) , acmIndex ) ;
2017-10-12 13:59:23 +08:00
}
else if ( ! bgBootPolicyFound ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: ACM and KeyManifest found, BootPolicy isn't " , __FUNCTION__ ) , kmIndex ) ;
2017-10-12 13:59:23 +08:00
}
else {
// Check key hashes
if ( ! bgKmHash . isEmpty ( ) & & bgBpHash . isEmpty ( ) & & bgKmHash ! = bgBpHash ) {
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: BootPolicy key hash stored in KeyManifest differs from the hash of public key stored in BootPolicy " , __FUNCTION__ ) , bpIndex ) ;
2017-10-12 13:59:23 +08:00
return U_SUCCESS ;
}
}
}
2016-07-15 03:22:51 +08:00
return U_SUCCESS ;
}
2019-02-02 00:45:39 +08:00
void FfsParser : : findFitRecursive ( const UModelIndex & index , UModelIndex & found , UINT32 & fitOffset )
2016-07-15 03:22:51 +08:00
{
// Sanity check
2018-04-30 13:33:19 +08:00
if ( ! index . isValid ( ) ) {
2019-02-02 00:45:39 +08:00
return ;
2018-04-30 13:33:19 +08:00
}
2016-07-15 03:22:51 +08:00
// Process child items
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2017-07-09 03:31:57 +08:00
findFitRecursive ( index . child ( i , 0 ) , found , fitOffset ) ;
2016-07-15 03:22:51 +08:00
if ( found . isValid ( ) )
2019-02-02 00:45:39 +08:00
return ;
2016-07-15 03:22:51 +08:00
}
// Check for all FIT signatures in item's body
UByteArray lastVtfBody = model - > body ( lastVtf ) ;
UINT32 storedFitAddress = * ( const UINT32 * ) ( lastVtfBody . constData ( ) + lastVtfBody . size ( ) - FIT_POINTER_OFFSET ) ;
for ( INT32 offset = model - > body ( index ) . indexOf ( FIT_SIGNATURE ) ;
offset > = 0 ;
offset = model - > body ( index ) . indexOf ( FIT_SIGNATURE , offset + 1 ) ) {
// FIT candidate found, calculate it's physical address
2019-01-07 21:05:57 +08:00
UINT32 fitAddress = model - > base ( index ) + ( UINT32 ) addressDiff + model - > header ( index ) . size ( ) + ( UINT32 ) offset ;
2016-07-15 03:22:51 +08:00
// Check FIT address to be stored in the last VTF
if ( fitAddress = = storedFitAddress ) {
found = index ;
fitOffset = offset ;
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: real FIT table found at physical address %08Xh " , __FUNCTION__ , fitAddress ) , found ) ;
2019-02-02 00:45:39 +08:00
break ;
2016-07-15 03:22:51 +08:00
}
else if ( model - > rowCount ( index ) = = 0 ) // Show messages only to leaf items
2018-04-30 13:33:19 +08:00
msg ( usprintf ( " %s: FIT table candidate found, but not referenced from the last VTF " , __FUNCTION__ ) , index ) ;
2016-07-15 03:22:51 +08:00
}
2015-03-13 14:48:53 +08:00
}
2018-10-08 17:58:12 +08:00
USTATUS FfsParser : : parseFitEntryMicrocode ( const UByteArray & microcode , const UINT32 localOffset , const UModelIndex & parent , UString & info , UINT32 & realSize )
2015-06-20 02:26:45 +08:00
{
2017-10-12 13:59:23 +08:00
U_UNUSED_PARAMETER ( parent ) ;
2019-09-05 08:07:18 +08:00
if ( ( UINT32 ) microcode . size ( ) - localOffset < sizeof ( INTEL_MICROCODE_HEADER ) ) {
2018-04-30 13:33:19 +08:00
return U_INVALID_MICROCODE ;
}
2019-09-05 08:07:18 +08:00
const INTEL_MICROCODE_HEADER * ucodeHeader = ( const INTEL_MICROCODE_HEADER * ) ( microcode . constData ( ) + localOffset ) ;
if ( ! microcodeHeaderValid ( ucodeHeader ) ) {
2019-07-25 01:30:59 +08:00
return U_INVALID_MICROCODE ;
}
2019-09-05 08:07:18 +08:00
if ( ( UINT32 ) microcode . size ( ) - localOffset < ucodeHeader - > TotalSize ) {
2019-07-25 01:30:59 +08:00
return U_INVALID_MICROCODE ;
}
2018-04-30 13:33:19 +08:00
// Valid microcode found
2019-07-25 01:30:59 +08:00
info = usprintf ( " CpuSignature: %08Xh, Revision: %08Xh, Date: %02X.%02X.%04X " ,
2019-09-07 04:16:26 +08:00
ucodeHeader - > ProcessorSignature ,
ucodeHeader - > UpdateRevision ,
2019-09-05 08:07:18 +08:00
ucodeHeader - > DateDay ,
ucodeHeader - > DateMonth ,
ucodeHeader - > DateYear ) ;
realSize = ucodeHeader - > TotalSize ;
2018-04-30 13:33:19 +08:00
return U_SUCCESS ;
2017-10-12 13:59:23 +08:00
}
2016-10-28 00:31:15 +08:00
2018-10-08 17:58:12 +08:00
USTATUS FfsParser : : parseFitEntryAcm ( const UByteArray & acm , const UINT32 localOffset , const UModelIndex & parent , UString & info , UINT32 & realSize )
2017-10-12 13:59:23 +08:00
{
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) acm . size ( ) < localOffset + sizeof ( INTEL_ACM_HEADER ) ) {
return U_INVALID_ACM ;
}
const INTEL_ACM_HEADER * header = ( const INTEL_ACM_HEADER * ) ( acm . constData ( ) + localOffset ) ;
if ( header - > ModuleType ! = INTEL_ACM_MODULE_TYPE | | header - > ModuleVendor ! = INTEL_ACM_MODULE_VENDOR ) {
return U_INVALID_ACM ;
}
UINT32 acmSize = header - > ModuleSize * sizeof ( UINT32 ) ;
if ( ( UINT32 ) acm . size ( ) < localOffset + acmSize ) {
return U_INVALID_ACM ;
}
// Valid ACM found
2018-10-08 17:58:12 +08:00
info = usprintf ( " LocalOffset: %08Xh, EntryPoint: %08Xh, ACM SVN: %04Xh, Date: %02X.%02X.%04X " ,
2017-10-12 13:59:23 +08:00
localOffset ,
header - > EntryPoint ,
header - > AcmSvn ,
header - > DateDay ,
header - > DateMonth ,
header - > DateYear
) ;
2018-04-30 13:33:19 +08:00
realSize = acmSize ;
// Add ACM header info
2018-10-08 17:58:12 +08:00
UString acmInfo ;
2019-07-25 01:30:59 +08:00
acmInfo + = usprintf ( " found at base %Xh \n "
" ModuleType: %04Xh ModuleSubtype: %04Xh HeaderLength: %08Xh \n "
" HeaderVersion: %08Xh ChipsetId: %04Xh Flags: %04Xh \n "
" ModuleVendor: %04Xh Date: %02X.%02X.%04X ModuleSize: %08Xh \n "
" EntryPoint: %08Xh AcmSvn: %04Xh Unknown1: %08Xh \n "
" Unknown2: %08Xh GdtBase: %08Xh GdtMax: %08Xh \n "
" SegSel: %08Xh KeySize: %08Xh Unknown3: %08Xh " ,
model - > base ( parent ) + localOffset ,
header - > ModuleType ,
header - > ModuleSubtype ,
header - > ModuleSize * sizeof ( UINT32 ) ,
header - > HeaderVersion ,
header - > ChipsetId ,
header - > Flags ,
header - > ModuleVendor ,
header - > DateDay , header - > DateMonth , header - > DateYear ,
header - > ModuleSize * sizeof ( UINT32 ) ,
header - > EntryPoint ,
header - > AcmSvn ,
header - > Unknown1 ,
header - > Unknown2 ,
header - > GdtBase ,
header - > GdtMax ,
header - > SegmentSel ,
header - > KeySize * sizeof ( UINT32 ) ,
header - > Unknown4 * sizeof ( UINT32 )
) ;
2018-04-30 13:33:19 +08:00
// Add PubKey
2018-10-08 17:58:12 +08:00
acmInfo + = usprintf ( " \n \n ACM RSA Public Key (Exponent: %Xh): " , header - > RsaPubExp ) ;
2018-04-30 13:33:19 +08:00
for ( UINT16 i = 0 ; i < sizeof ( header - > RsaPubKey ) ; i + + ) {
if ( i % 32 = = 0 )
2018-10-08 17:58:12 +08:00
acmInfo + = UString ( " \n " ) ;
acmInfo + = usprintf ( " %02X " , header - > RsaPubKey [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
// Add RsaSig
2018-10-08 17:58:12 +08:00
acmInfo + = UString ( " \n \n ACM RSA Signature: " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT16 i = 0 ; i < sizeof ( header - > RsaSig ) ; i + + ) {
if ( i % 32 = = 0 )
2018-10-08 17:58:12 +08:00
acmInfo + = UString ( " \n " ) ;
acmInfo + = usprintf ( " %02X " , header - > RsaSig [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
2018-10-08 17:58:12 +08:00
acmInfo + = UString ( " \n ------------------------------------------------------------------------ \n \n " ) ;
if ( header - > ModuleSubtype = = INTEL_ACM_MODULE_SUBTYPE_TXT_ACM )
securityInfo + = " TXT ACM " + acmInfo ;
else if ( header - > ModuleSubtype = = INTEL_ACM_MODULE_SUBTYPE_S_ACM )
securityInfo + = " S-ACM " + acmInfo ;
else if ( header - > ModuleSubtype = = INTEL_ACM_MODULE_SUBTYPE_BOOTGUARD )
securityInfo + = " BootGuard ACM " + acmInfo ;
else
securityInfo + = " Intel ACM " + acmInfo ;
2018-04-30 13:33:19 +08:00
bgAcmFound = true ;
return U_SUCCESS ;
2017-10-12 13:59:23 +08:00
}
2015-06-20 02:26:45 +08:00
2018-10-08 17:58:12 +08:00
USTATUS FfsParser : : parseFitEntryBootGuardKeyManifest ( const UByteArray & keyManifest , const UINT32 localOffset , const UModelIndex & parent , UString & info , UINT32 & realSize )
2017-10-12 13:59:23 +08:00
{
U_UNUSED_PARAMETER ( realSize ) ;
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) keyManifest . size ( ) < localOffset + sizeof ( BG_KEY_MANIFEST ) ) {
return U_INVALID_BG_KEY_MANIFEST ;
}
const BG_KEY_MANIFEST * header = ( const BG_KEY_MANIFEST * ) ( keyManifest . constData ( ) + localOffset ) ;
if ( header - > Tag ! = BG_KEY_MANIFEST_TAG ) {
return U_INVALID_BG_KEY_MANIFEST ;
}
2017-10-12 13:59:23 +08:00
2018-04-30 13:33:19 +08:00
// Valid KM found
2018-10-08 17:58:12 +08:00
info = usprintf ( " LocalOffset: %08Xh, KM Version: %02Xh, KM SVN: %02Xh, KM ID: %02Xh " ,
2018-04-30 13:33:19 +08:00
localOffset ,
2017-10-12 13:59:23 +08:00
header - > KmVersion ,
header - > KmSvn ,
header - > KmId
) ;
2017-12-11 09:56:00 +08:00
2018-04-30 13:33:19 +08:00
// Add KM header info
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf (
2019-01-07 21:05:57 +08:00
" Intel BootGuard Key manifest found at base %Xh \n "
2018-04-30 13:33:19 +08:00
" Tag: __KEYM__ Version: %02Xh KmVersion: %02Xh KmSvn: %02Xh KmId: %02Xh " ,
2019-01-07 21:05:57 +08:00
model - > base ( parent ) + localOffset ,
2018-04-30 13:33:19 +08:00
header - > Version ,
header - > KmVersion ,
header - > KmSvn ,
header - > KmId
) ;
// Add hash of Key Manifest PubKey, this hash will be written to FPFs
UINT8 hash [ SHA256_DIGEST_SIZE ] ;
sha256 ( & header - > KeyManifestSignature . PubKey . Modulus , sizeof ( header - > KeyManifestSignature . PubKey . Modulus ) , hash ) ;
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n \n Key Manifest RSA Public Key Hash: \n " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT8 i = 0 ; i < sizeof ( hash ) ; i + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " %02X " , hash [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
// Add BpKeyHash
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n \n Boot Policy RSA Public Key Hash: \n " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT8 i = 0 ; i < sizeof ( header - > BpKeyHash . HashBuffer ) ; i + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " %02X " , header - > BpKeyHash . HashBuffer [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
bgKmHash = UByteArray ( ( const char * ) header - > BpKeyHash . HashBuffer , sizeof ( header - > BpKeyHash . HashBuffer ) ) ;
// Add Key Manifest PubKey
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " \n \n Key Manifest RSA Public Key (Exponent: %Xh): " ,
2018-04-30 13:33:19 +08:00
header - > KeyManifestSignature . PubKey . Exponent ) ;
for ( UINT16 i = 0 ; i < sizeof ( header - > KeyManifestSignature . PubKey . Modulus ) ; i + + ) {
if ( i % 32 = = 0 )
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n " ) ;
securityInfo + = usprintf ( " %02X " , header - > KeyManifestSignature . PubKey . Modulus [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
// Add Key Manifest Signature
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n \n Key Manifest RSA Signature: " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT16 i = 0 ; i < sizeof ( header - > KeyManifestSignature . Signature . Signature ) ; i + + ) {
if ( i % 32 = = 0 )
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n " ) ;
securityInfo + = usprintf ( " %02X " , header - > KeyManifestSignature . Signature . Signature [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n ------------------------------------------------------------------------ \n \n " ) ;
2018-04-30 13:33:19 +08:00
bgKeyManifestFound = true ;
return U_SUCCESS ;
2017-10-12 13:59:23 +08:00
}
2018-10-08 17:58:12 +08:00
USTATUS FfsParser : : findNextBootGuardBootPolicyElement ( const UByteArray & bootPolicy , const UINT32 elementOffset , UINT32 & nextElementOffset , UINT32 & nextElementSize )
2017-10-12 13:59:23 +08:00
{
UINT32 dataSize = bootPolicy . size ( ) ;
2018-04-30 13:33:19 +08:00
if ( dataSize < sizeof ( UINT64 ) ) {
2017-10-12 13:59:23 +08:00
return U_ELEMENTS_NOT_FOUND ;
2018-04-30 13:33:19 +08:00
}
2017-10-12 13:59:23 +08:00
UINT32 offset = elementOffset ;
for ( ; offset < dataSize - sizeof ( UINT64 ) ; offset + + ) {
const UINT64 * currentPos = ( const UINT64 * ) ( bootPolicy . constData ( ) + offset ) ;
if ( * currentPos = = BG_BOOT_POLICY_MANIFEST_IBB_ELEMENT_TAG & & offset + sizeof ( BG_IBB_ELEMENT ) < dataSize ) {
const BG_IBB_ELEMENT * header = ( const BG_IBB_ELEMENT * ) currentPos ;
// Check that all segments are present
if ( offset + sizeof ( BG_IBB_ELEMENT ) + sizeof ( BG_IBB_SEGMENT_ELEMENT ) * header - > IbbSegCount < dataSize ) {
nextElementOffset = offset ;
nextElementSize = sizeof ( BG_IBB_ELEMENT ) + sizeof ( BG_IBB_SEGMENT_ELEMENT ) * header - > IbbSegCount ;
return U_SUCCESS ;
}
}
else if ( * currentPos = = BG_BOOT_POLICY_MANIFEST_PLATFORM_MANUFACTURER_ELEMENT_TAG & & offset + sizeof ( BG_PLATFORM_MANUFACTURER_ELEMENT ) < dataSize ) {
2017-11-06 15:10:06 +08:00
const BG_PLATFORM_MANUFACTURER_ELEMENT * header = ( const BG_PLATFORM_MANUFACTURER_ELEMENT * ) currentPos ;
2017-10-12 13:59:23 +08:00
// Check that data is present
if ( offset + sizeof ( BG_PLATFORM_MANUFACTURER_ELEMENT ) + header - > DataSize < dataSize ) {
nextElementOffset = offset ;
nextElementSize = sizeof ( BG_PLATFORM_MANUFACTURER_ELEMENT ) + header - > DataSize ;
return U_SUCCESS ;
}
}
else if ( * currentPos = = BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT_TAG & & offset + sizeof ( BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT ) < dataSize ) {
nextElementOffset = offset ;
nextElementSize = sizeof ( BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT ) ;
return U_SUCCESS ;
}
2016-01-28 07:21:51 +08:00
}
2017-10-12 13:59:23 +08:00
return U_ELEMENTS_NOT_FOUND ;
2016-01-28 07:21:51 +08:00
}
2018-10-08 17:58:12 +08:00
USTATUS FfsParser : : parseFitEntryBootGuardBootPolicy ( const UByteArray & bootPolicy , const UINT32 localOffset , const UModelIndex & parent , UString & info , UINT32 & realSize )
2016-01-28 07:21:51 +08:00
{
2017-10-12 13:59:23 +08:00
U_UNUSED_PARAMETER ( realSize ) ;
2018-04-30 13:33:19 +08:00
if ( ( UINT32 ) bootPolicy . size ( ) < localOffset + sizeof ( BG_BOOT_POLICY_MANIFEST_HEADER ) ) {
return U_INVALID_BG_BOOT_POLICY ;
}
const BG_BOOT_POLICY_MANIFEST_HEADER * header = ( const BG_BOOT_POLICY_MANIFEST_HEADER * ) ( bootPolicy . constData ( ) + localOffset ) ;
if ( header - > Tag ! = BG_BOOT_POLICY_MANIFEST_HEADER_TAG ) {
return U_INVALID_BG_BOOT_POLICY ;
}
UINT32 bmSize = sizeof ( BG_BOOT_POLICY_MANIFEST_HEADER ) ;
if ( ( UINT32 ) bootPolicy . size ( ) < localOffset + bmSize ) {
return U_INVALID_BG_BOOT_POLICY ;
}
// Valid BPM found
2018-10-08 17:58:12 +08:00
info = usprintf ( " LocalOffset: %08Xh, BP SVN: %02Xh, ACM SVN: %02Xh " ,
2017-10-12 13:59:23 +08:00
localOffset ,
header - > BPSVN ,
header - > ACMSVN
) ;
2018-04-30 13:33:19 +08:00
// Add BP header info
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf (
2019-01-07 21:05:57 +08:00
" Intel BootGuard Boot Policy Manifest found at base %Xh \n "
2018-04-30 13:33:19 +08:00
" Tag: __ACBP__ Version: %02Xh HeaderVersion: %02Xh \n "
" PMBPMVersion: %02Xh PBSVN: %02Xh ACMSVN: %02Xh NEMDataStack: %04Xh \n " ,
2019-01-07 21:05:57 +08:00
model - > base ( parent ) + localOffset ,
2018-04-30 13:33:19 +08:00
header - > Version ,
header - > HeaderVersion ,
header - > PMBPMVersion ,
header - > BPSVN ,
header - > ACMSVN ,
header - > NEMDataSize
) ;
// Iterate over elements to get them all
UINT32 elementOffset = 0 ;
UINT32 elementSize = 0 ;
2018-10-08 17:58:12 +08:00
USTATUS status = findNextBootGuardBootPolicyElement ( bootPolicy , localOffset + sizeof ( BG_BOOT_POLICY_MANIFEST_HEADER ) , elementOffset , elementSize ) ;
2018-04-30 13:33:19 +08:00
while ( status = = U_SUCCESS ) {
const UINT64 * currentPos = ( const UINT64 * ) ( bootPolicy . constData ( ) + elementOffset ) ;
if ( * currentPos = = BG_BOOT_POLICY_MANIFEST_IBB_ELEMENT_TAG ) {
const BG_IBB_ELEMENT * elementHeader = ( const BG_IBB_ELEMENT * ) currentPos ;
// Valid IBB element found
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf (
2019-01-07 21:05:57 +08:00
" \n Initial Boot Block Element found at base %Xh \n "
2018-04-30 13:33:19 +08:00
" Tag: __IBBS__ Version: %02Xh Unknown: %02Xh \n "
" Flags: %08Xh IbbMchBar: %08Xh VtdBar: %08Xh \n "
" PmrlBase: %08Xh PmrlLimit: %08Xh EntryPoint: %08Xh " ,
2019-01-07 21:05:57 +08:00
model - > base ( parent ) + localOffset + elementOffset ,
2018-04-30 13:33:19 +08:00
elementHeader - > Version ,
elementHeader - > Unknown ,
elementHeader - > Flags ,
elementHeader - > IbbMchBar ,
elementHeader - > VtdBar ,
elementHeader - > PmrlBase ,
elementHeader - > PmrlLimit ,
elementHeader - > EntryPoint
) ;
// Add PostIbbHash
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n \n Post IBB Hash: \n " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT8 i = 0 ; i < sizeof ( elementHeader - > IbbHash . HashBuffer ) ; i + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " %02X " , elementHeader - > IbbHash . HashBuffer [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
2017-10-12 13:59:23 +08:00
2018-04-30 13:33:19 +08:00
// Check for non-empry PostIbbHash
UByteArray postIbbHash ( ( const char * ) elementHeader - > IbbHash . HashBuffer , sizeof ( elementHeader - > IbbHash . HashBuffer ) ) ;
if ( postIbbHash . count ( ' \x00 ' ) ! = postIbbHash . size ( ) & & postIbbHash . count ( ' \xFF ' ) ! = postIbbHash . size ( ) ) {
BG_PROTECTED_RANGE range ;
range . Type = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB ;
range . Hash = postIbbHash ;
bgProtectedRanges . push_back ( range ) ;
}
2017-12-11 09:56:00 +08:00
2018-04-30 13:33:19 +08:00
// Add Digest
bgBpDigest = UByteArray ( ( const char * ) elementHeader - > Digest . HashBuffer , sizeof ( elementHeader - > Digest . HashBuffer ) ) ;
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n \n IBB Digest: \n " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT8 i = 0 ; i < ( UINT8 ) bgBpDigest . size ( ) ; i + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " %02X " , ( UINT8 ) bgBpDigest . at ( i ) ) ;
2018-04-30 13:33:19 +08:00
}
2017-12-11 09:56:00 +08:00
2018-04-30 13:33:19 +08:00
// Add all IBB segments
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n \n IBB Segments: \n " ) ;
2018-04-30 13:33:19 +08:00
const BG_IBB_SEGMENT_ELEMENT * segments = ( const BG_IBB_SEGMENT_ELEMENT * ) ( elementHeader + 1 ) ;
for ( UINT8 i = 0 ; i < elementHeader - > IbbSegCount ; i + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " Flags: %04Xh Address: %08Xh Size: %08Xh \n " ,
2018-04-30 13:33:19 +08:00
segments [ i ] . Flags , segments [ i ] . Base , segments [ i ] . Size ) ;
if ( segments [ i ] . Flags = = BG_IBB_SEGMENT_FLAG_IBB ) {
BG_PROTECTED_RANGE range ;
range . Offset = segments [ i ] . Base ;
range . Size = segments [ i ] . Size ;
range . Type = BG_PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB ;
bgProtectedRanges . push_back ( range ) ;
}
}
}
else if ( * currentPos = = BG_BOOT_POLICY_MANIFEST_PLATFORM_MANUFACTURER_ELEMENT_TAG ) {
const BG_PLATFORM_MANUFACTURER_ELEMENT * elementHeader = ( const BG_PLATFORM_MANUFACTURER_ELEMENT * ) currentPos ;
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf (
2019-01-07 21:05:57 +08:00
" \n Platform Manufacturer Data Element found at base %Xh \n "
2018-04-30 13:33:19 +08:00
" Tag: __PMDA__ Version: %02Xh DataSize: %02Xh " ,
2019-01-07 21:05:57 +08:00
model - > base ( parent ) + localOffset + elementOffset ,
2018-04-30 13:33:19 +08:00
elementHeader - > Version ,
elementHeader - > DataSize
) ;
// Check for Microsoft PMDA hash data
2018-05-08 23:42:16 +08:00
const BG_MICROSOFT_PMDA_HEADER * pmdaHeader = ( const BG_MICROSOFT_PMDA_HEADER * ) ( elementHeader + 1 ) ;
if ( pmdaHeader - > Version = = BG_MICROSOFT_PMDA_VERSION
& & elementHeader - > DataSize = = sizeof ( BG_MICROSOFT_PMDA_HEADER ) + sizeof ( BG_MICROSOFT_PMDA_ENTRY ) * pmdaHeader - > NumEntries ) {
2018-04-30 13:33:19 +08:00
// Add entries
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n Microsoft PMDA-based protected ranges: \n " ) ;
2018-05-08 23:42:16 +08:00
const BG_MICROSOFT_PMDA_ENTRY * entries = ( const BG_MICROSOFT_PMDA_ENTRY * ) ( pmdaHeader + 1 ) ;
for ( UINT32 i = 0 ; i < pmdaHeader - > NumEntries ; i + + ) {
2016-01-28 07:21:51 +08:00
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " Address: %08Xh Size: %08Xh \n " , entries [ i ] . Address , entries [ i ] . Size ) ;
securityInfo + = UString ( " Hash: " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT8 j = 0 ; j < sizeof ( entries [ i ] . Hash ) ; j + + ) {
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " %02X " , entries [ i ] . Hash [ j ] ) ;
2017-10-12 13:59:23 +08:00
}
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n " ) ;
2017-10-12 13:59:23 +08:00
2018-04-30 13:33:19 +08:00
BG_PROTECTED_RANGE range ;
range . Offset = entries [ i ] . Address ;
range . Size = entries [ i ] . Size ;
range . Hash = UByteArray ( ( const char * ) entries [ i ] . Hash , sizeof ( entries [ i ] . Hash ) ) ;
range . Type = BG_PROTECTED_RANGE_VENDOR_HASH_MICROSOFT ;
bgProtectedRanges . push_back ( range ) ;
2017-10-12 13:59:23 +08:00
}
2018-04-30 13:33:19 +08:00
}
else {
// Add raw data
const UINT8 * data = ( const UINT8 * ) ( elementHeader + 1 ) ;
for ( UINT16 i = 0 ; i < elementHeader - > DataSize ; i + + ) {
if ( i % 32 = = 0 )
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n " ) ;
securityInfo + = usprintf ( " %02X " , data [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n " ) ;
2018-04-30 13:33:19 +08:00
}
}
else if ( * currentPos = = BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT_TAG ) {
const BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT * elementHeader = ( const BG_BOOT_POLICY_MANIFEST_SIGNATURE_ELEMENT * ) currentPos ;
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf (
2019-01-07 21:05:57 +08:00
" \n Boot Policy Signature Element found at base %Xh \n "
2018-04-30 13:33:19 +08:00
" Tag: __PMSG__ Version: %02Xh " ,
2019-01-07 21:05:57 +08:00
model - > base ( parent ) + localOffset + elementOffset ,
2018-04-30 13:33:19 +08:00
elementHeader - > Version
) ;
// Add PubKey
2018-10-08 17:58:12 +08:00
securityInfo + = usprintf ( " \n \n Boot Policy RSA Public Key (Exponent: %Xh): " , elementHeader - > KeySignature . PubKey . Exponent ) ;
2018-04-30 13:33:19 +08:00
for ( UINT16 i = 0 ; i < sizeof ( elementHeader - > KeySignature . PubKey . Modulus ) ; i + + ) {
if ( i % 32 = = 0 )
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n " ) ;
securityInfo + = usprintf ( " %02X " , elementHeader - > KeySignature . PubKey . Modulus [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
2017-10-12 13:59:23 +08:00
2018-04-30 13:33:19 +08:00
// Calculate and add PubKey hash
UINT8 hash [ SHA256_DIGEST_SIZE ] ;
sha256 ( & elementHeader - > KeySignature . PubKey . Modulus , sizeof ( elementHeader - > KeySignature . PubKey . Modulus ) , hash ) ;
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n \n Boot Policy RSA Public Key Hash: " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT8 i = 0 ; i < sizeof ( hash ) ; i + + ) {
if ( i % 32 = = 0 )
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n " ) ;
securityInfo + = usprintf ( " %02X " , hash [ i ] ) ;
2018-04-30 13:33:19 +08:00
}
bgBpHash = UByteArray ( ( const char * ) hash , sizeof ( hash ) ) ;
// Add Signature
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n \n Boot Policy RSA Signature: " ) ;
2018-04-30 13:33:19 +08:00
for ( UINT16 i = 0 ; i < sizeof ( elementHeader - > KeySignature . Signature . Signature ) ; i + + ) {
if ( i % 32 = = 0 )
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n " ) ;
securityInfo + = usprintf ( " %02X " , elementHeader - > KeySignature . Signature . Signature [ i ] ) ;
2017-10-12 13:59:23 +08:00
}
}
2018-10-08 17:58:12 +08:00
status = findNextBootGuardBootPolicyElement ( bootPolicy , elementOffset + elementSize , elementOffset , elementSize ) ;
2015-06-20 02:26:45 +08:00
}
2018-10-08 17:58:12 +08:00
securityInfo + = UString ( " \n ------------------------------------------------------------------------ \n \n " ) ;
2018-04-30 13:33:19 +08:00
bgBootPolicyFound = true ;
return U_SUCCESS ;
2015-07-05 12:20:03 +08:00
}
2017-10-12 13:59:23 +08:00
# endif
2018-04-30 13:33:19 +08:00
2018-10-08 17:58:12 +08:00
USTATUS FfsParser : : parseMicrocodeVolumeBody ( const UModelIndex & index )
{
const UINT32 headerSize = ( UINT32 ) model - > header ( index ) . size ( ) ;
const UINT32 bodySize = ( UINT32 ) model - > body ( index ) . size ( ) ;
UINT32 offset = 0 ;
USTATUS result = U_SUCCESS ;
while ( true ) {
// Parse current microcode
UModelIndex currentMicrocode ;
UByteArray ucode = model - > body ( index ) . mid ( offset ) ;
// Check for empty area
if ( ucode . size ( ) = = ucode . count ( ' \xFF ' ) | | ucode . size ( ) = = ucode . count ( ' \x00 ' ) ) {
result = U_INVALID_MICROCODE ;
}
else {
result = parseIntelMicrocodeHeader ( ucode , headerSize + offset , index , currentMicrocode ) ;
}
// Add the rest as padding
if ( result ) {
if ( offset < bodySize ) {
// Get info
UString name = UString ( " Padding " ) ;
UString info = usprintf ( " Full size: %Xh (%u) " , ucode . size ( ) , ucode . size ( ) ) ;
// Add tree item
2019-01-07 21:05:57 +08:00
model - > addItem ( headerSize + offset , Types : : Padding , getPaddingType ( ucode ) , name , UString ( ) , info , UByteArray ( ) , ucode , UByteArray ( ) , Fixed , index ) ;
2018-10-08 17:58:12 +08:00
}
return U_SUCCESS ;
}
// Get to next candidate
offset + = model - > header ( currentMicrocode ) . size ( ) + model - > body ( currentMicrocode ) . size ( ) + model - > tail ( currentMicrocode ) . size ( ) ;
if ( offset > = bodySize )
break ;
}
return U_SUCCESS ;
}
USTATUS FfsParser : : parseIntelMicrocodeHeader ( const UByteArray & microcode , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
{
2019-07-25 01:30:59 +08:00
// We have enough data to fit the header
if ( ( UINT32 ) microcode . size ( ) < sizeof ( INTEL_MICROCODE_HEADER ) ) {
2018-10-08 17:58:12 +08:00
return U_INVALID_MICROCODE ;
}
const INTEL_MICROCODE_HEADER * ucodeHeader = ( const INTEL_MICROCODE_HEADER * ) microcode . constData ( ) ;
2019-07-25 01:30:59 +08:00
2019-09-05 08:07:18 +08:00
if ( ! microcodeHeaderValid ( ucodeHeader ) ) {
2018-10-08 17:58:12 +08:00
return U_INVALID_MICROCODE ;
}
2019-07-25 01:30:59 +08:00
// We have enough data to fit the whole TotalSize
if ( ( UINT32 ) microcode . size ( ) < ucodeHeader - > TotalSize ) {
2018-10-08 17:58:12 +08:00
return U_INVALID_MICROCODE ;
}
2019-09-05 08:07:18 +08:00
2018-10-08 17:58:12 +08:00
// Valid microcode found
2019-07-25 01:30:59 +08:00
UINT32 dataSize = ucodeHeader - > DataSize ;
2019-09-06 03:25:47 +08:00
if ( dataSize = = 0 ) {
2019-07-25 01:30:59 +08:00
dataSize = INTEL_MICROCODE_REAL_DATA_SIZE_ON_ZERO ;
2019-09-06 03:25:47 +08:00
}
2019-07-25 01:30:59 +08:00
// Recalculate the whole microcode checksum
UByteArray tempMicrocode = microcode ;
INTEL_MICROCODE_HEADER * tempUcodeHeader = ( INTEL_MICROCODE_HEADER * ) ( tempMicrocode . data ( ) ) ;
tempUcodeHeader - > Checksum = 0 ;
UINT32 calculated = calculateChecksum32 ( ( const UINT32 * ) tempMicrocode . constData ( ) , tempUcodeHeader - > TotalSize ) ;
bool msgInvalidChecksum = ( ucodeHeader - > Checksum ! = calculated ) ;
// Construct header, body and tail
2018-10-08 17:58:12 +08:00
UByteArray header = microcode . left ( sizeof ( INTEL_MICROCODE_HEADER ) ) ;
2019-07-25 01:30:59 +08:00
UByteArray body = microcode . mid ( sizeof ( INTEL_MICROCODE_HEADER ) , dataSize ) ;
UByteArray tail = microcode . mid ( sizeof ( INTEL_MICROCODE_HEADER ) + dataSize ) ;
// Check if we have extended header in the tail
UString extendedHeaderInfo ;
if ( ( UINT32 ) tail . size ( ) > = sizeof ( INTEL_MICROCODE_EXTENDED_HEADER ) ) {
const INTEL_MICROCODE_EXTENDED_HEADER * extendedHeader = ( const INTEL_MICROCODE_EXTENDED_HEADER * ) tail . constData ( ) ;
// Reserved bytes are all zeroes
bool extendedReservedBytesValid = true ;
for ( UINT8 i = 0 ; i < sizeof ( extendedHeader - > Reserved ) ; i + + ) {
if ( extendedHeader - > Reserved [ i ] ! = 0x00 ) {
extendedReservedBytesValid = false ;
break ;
}
}
// We have more than 0 entries and they are all in the tail
if ( extendedReservedBytesValid
& & extendedHeader - > EntryCount > 0
& & ( UINT32 ) tail . size ( ) > = sizeof ( INTEL_MICROCODE_EXTENDED_HEADER ) + extendedHeader - > EntryCount * sizeof ( INTEL_MICROCODE_EXTENDED_HEADER_ENTRY ) ) {
// Recalculate extended header checksum
INTEL_MICROCODE_EXTENDED_HEADER * tempExtendedHeader = ( INTEL_MICROCODE_EXTENDED_HEADER * ) ( tempMicrocode . data ( ) + sizeof ( INTEL_MICROCODE_HEADER ) + dataSize ) ;
tempExtendedHeader - > Checksum = 0 ;
UINT32 extendedCalculated = calculateChecksum32 ( ( const UINT32 * ) tempExtendedHeader , sizeof ( INTEL_MICROCODE_EXTENDED_HEADER ) + extendedHeader - > EntryCount * sizeof ( INTEL_MICROCODE_EXTENDED_HEADER_ENTRY ) ) ;
extendedHeaderInfo = usprintf ( " \n Extended header entries: %u \n Extended header checksum: %08Xh, " ,
extendedHeader - > EntryCount ,
extendedHeader - > Checksum )
+ ( extendedHeader - > Checksum = = extendedCalculated ? UString ( " valid " ) : usprintf ( " invalid, should be %08Xh " , extendedCalculated ) ) ;
const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY * firstEntry = ( const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY * ) ( extendedHeader + 1 ) ;
for ( UINT8 i = 0 ; i < extendedHeader - > EntryCount ; i + + ) {
const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY * entry = ( const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY * ) ( firstEntry + i ) ;
// Recalculate checksum after patching
tempUcodeHeader - > Checksum = 0 ;
2019-09-07 04:16:26 +08:00
tempUcodeHeader - > ProcessorFlags = entry - > ProcessorFlags ;
tempUcodeHeader - > ProcessorSignature = entry - > ProcessorSignature ;
2019-07-25 01:30:59 +08:00
UINT32 entryCalculated = calculateChecksum32 ( ( const UINT32 * ) tempMicrocode . constData ( ) , sizeof ( INTEL_MICROCODE_HEADER ) + dataSize ) ;
2019-09-05 08:07:18 +08:00
extendedHeaderInfo + = usprintf ( " \n CPU signature #%u: %08Xh \n CPU flags #%u: %02Xh \n Checksum #%u: %08Xh, " ,
2019-09-07 04:16:26 +08:00
i + 1 , entry - > ProcessorSignature ,
i + 1 , entry - > ProcessorFlags ,
2019-07-25 01:30:59 +08:00
i + 1 , entry - > Checksum )
+ ( entry - > Checksum = = entryCalculated ? UString ( " valid " ) : usprintf ( " invalid, should be %08Xh " , entryCalculated ) ) ;
}
}
}
2018-10-08 17:58:12 +08:00
// Add info
UString name ( " Intel microcode " ) ;
2019-07-25 01:30:59 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Tail size: %Xh (%u) \n "
2019-09-06 04:38:53 +08:00
" Date: %02X.%02X.%04x \n CPU signature: %08Xh \n Revision: %08Xh \n CPU flags: %02Xh \n Checksum: %08Xh, " ,
2019-07-25 01:30:59 +08:00
dataSize , dataSize ,
header . size ( ) , header . size ( ) ,
body . size ( ) , body . size ( ) ,
tail . size ( ) , tail . size ( ) ,
ucodeHeader - > DateDay ,
ucodeHeader - > DateMonth ,
ucodeHeader - > DateYear ,
2019-09-07 04:16:26 +08:00
ucodeHeader - > ProcessorSignature ,
ucodeHeader - > UpdateRevision ,
ucodeHeader - > ProcessorFlags ,
2019-07-25 01:30:59 +08:00
ucodeHeader - > Checksum )
+ ( ucodeHeader - > Checksum = = calculated ? UString ( " valid " ) : usprintf ( " invalid, should be %08Xh " , calculated ) )
+ extendedHeaderInfo ;
2018-10-08 17:58:12 +08:00
// Add tree item
2019-07-25 01:30:59 +08:00
index = model - > addItem ( localOffset , Types : : Microcode , Subtypes : : IntelMicrocode , name , UString ( ) , info , header , body , tail , Fixed , parent ) ;
if ( msgInvalidChecksum )
msg ( usprintf ( " %s: invalid microcode checksum %08Xh, should be %08Xh " , __FUNCTION__ , ucodeHeader - > Checksum , calculated ) , index ) ;
// No need to parse the body further for now
2018-10-08 17:58:12 +08:00
return U_SUCCESS ;
}
2019-08-20 02:36:02 +08:00
USTATUS FfsParser : : parseBpdtRegion ( const UByteArray & region , const UINT32 localOffset , const UINT32 sbpdtOffsetFixup , const UModelIndex & parent , UModelIndex & index )
{
UINT32 regionSize = ( UINT32 ) region . size ( ) ;
// Check region size
if ( regionSize < sizeof ( BPDT_HEADER ) ) {
msg ( usprintf ( " %s: BPDT region too small to fit BPDT partition table header " , __FUNCTION__ ) , parent ) ;
return U_INVALID_ME_PARTITION_TABLE ;
}
// Populate partition table header
const BPDT_HEADER * ptHeader = ( const BPDT_HEADER * ) ( region . constData ( ) ) ;
// Check region size again
UINT32 ptBodySize = ptHeader - > NumEntries * sizeof ( BPDT_ENTRY ) ;
UINT32 ptSize = sizeof ( BPDT_HEADER ) + ptBodySize ;
if ( regionSize < ptSize ) {
msg ( usprintf ( " %s: BPDT region too small to fit BPDT partition table " , __FUNCTION__ ) , parent ) ;
return U_INVALID_ME_PARTITION_TABLE ;
}
// Get info
UByteArray header = region . left ( sizeof ( BPDT_HEADER ) ) ;
UByteArray body = region . mid ( sizeof ( BPDT_HEADER ) , ptBodySize ) ;
UString name = UString ( " BPDT partition table " ) ;
UString info = usprintf ( " Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Number of entries: %u \n Version: %2Xh \n "
" IFWI version: %Xh \n FITC version: %u.%u.%u.%u " ,
ptSize , ptSize ,
header . size ( ) , header . size ( ) ,
ptBodySize , ptBodySize ,
ptHeader - > NumEntries ,
ptHeader - > HeaderVersion ,
ptHeader - > IfwiVersion ,
ptHeader - > FitcMajor , ptHeader - > FitcMinor , ptHeader - > FitcHotfix , ptHeader - > FitcBuild ) ;
// Add tree item
index = model - > addItem ( localOffset , Types : : BpdtStore , 0 , name , UString ( ) , info , header , body , UByteArray ( ) , Fixed , parent ) ;
// Adjust offset
UINT32 offset = sizeof ( BPDT_HEADER ) ;
// Add partition table entries
std : : vector < BPDT_PARTITION_INFO > partitions ;
const BPDT_ENTRY * firstPtEntry = ( const BPDT_ENTRY * ) ( ( const UINT8 * ) ptHeader + sizeof ( BPDT_HEADER ) ) ;
for ( UINT16 i = 0 ; i < ptHeader - > NumEntries ; i + + ) {
// Populate entry header
const BPDT_ENTRY * ptEntry = firstPtEntry + i ;
// Get info
name = bpdtEntryTypeToUString ( ptEntry - > Type ) ;
info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh \n Partition offset: %Xh \n Partition length: %Xh " ,
sizeof ( BPDT_ENTRY ) , sizeof ( BPDT_ENTRY ) ,
ptEntry - > Type ,
ptEntry - > Offset ,
ptEntry - > Size ) +
UString ( " \n Split sub-partition first part: " ) + ( ptEntry - > SplitSubPartitionFirstPart ? " Yes " : " No " ) +
UString ( " \n Split sub-partition second part: " ) + ( ptEntry - > SplitSubPartitionSecondPart ? " Yes " : " No " ) +
UString ( " \n Code sub-partition: " ) + ( ptEntry - > CodeSubPartition ? " Yes " : " No " ) +
UString ( " \n UMA cachable: " ) + ( ptEntry - > UmaCachable ? " Yes " : " No " ) ;
// Add tree item
UModelIndex entryIndex = model - > addItem ( localOffset + offset , Types : : BpdtEntry , 0 , name , UString ( ) , info , UByteArray ( ) , UByteArray ( ( const char * ) ptEntry , sizeof ( BPDT_ENTRY ) ) , UByteArray ( ) , Fixed , index ) ;
// Adjust offset
offset + = sizeof ( BPDT_ENTRY ) ;
if ( ptEntry - > Offset ! = 0 & & ptEntry - > Offset ! = 0xFFFFFFFF & & ptEntry - > Size ! = 0 ) {
// Add to partitions vector
BPDT_PARTITION_INFO partition ;
partition . type = Types : : BpdtPartition ;
partition . ptEntry = * ptEntry ;
partition . ptEntry . Offset - = sbpdtOffsetFixup ;
partition . index = entryIndex ;
partitions . push_back ( partition ) ;
}
}
// Add padding if there's no partions to add
if ( partitions . size ( ) = = 0 ) {
UByteArray partition = region . mid ( ptSize ) ;
// Get info
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " ,
partition . size ( ) , partition . size ( ) ) ;
// Add tree item
model - > addItem ( localOffset + ptSize , Types : : Padding , getPaddingType ( partition ) , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
return U_SUCCESS ;
}
make_partition_table_consistent :
// Sort partitions by offset
std : : sort ( partitions . begin ( ) , partitions . end ( ) ) ;
// Check for intersections and paddings between partitions
BPDT_PARTITION_INFO padding ;
// Check intersection with the partition table header
if ( partitions . front ( ) . ptEntry . Offset < ptSize ) {
msg ( usprintf ( " %s: BPDT partition has intersection with BPDT partition table, skipped " , __FUNCTION__ ) ,
partitions . front ( ) . index ) ;
partitions . erase ( partitions . begin ( ) ) ;
goto make_partition_table_consistent ;
}
// Check for padding between partition table and the first partition
else if ( partitions . front ( ) . ptEntry . Offset > ptSize ) {
padding . ptEntry . Offset = ptSize ;
padding . ptEntry . Size = partitions . front ( ) . ptEntry . Offset - padding . ptEntry . Offset ;
padding . type = Types : : Padding ;
partitions . insert ( partitions . begin ( ) , padding ) ;
}
// Check for intersections/paddings between partitions
for ( size_t i = 1 ; i < partitions . size ( ) ; i + + ) {
UINT32 previousPartitionEnd = partitions [ i - 1 ] . ptEntry . Offset + partitions [ i - 1 ] . ptEntry . Size ;
// Check that partition is fully present in the image
if ( ( UINT64 ) partitions [ i ] . ptEntry . Offset + ( UINT64 ) partitions [ i ] . ptEntry . Size > regionSize ) {
if ( ( UINT64 ) partitions [ i ] . ptEntry . Offset > = ( UINT64 ) region . size ( ) ) {
msg ( usprintf ( " %s: BPDT partition is located outside of the opened image, skipped " , __FUNCTION__ ) , partitions [ i ] . index ) ;
partitions . erase ( partitions . begin ( ) + i ) ;
goto make_partition_table_consistent ;
}
else {
msg ( usprintf ( " %s: BPDT partition can't fit into it's region, truncated " , __FUNCTION__ ) , partitions [ i ] . index ) ;
partitions [ i ] . ptEntry . Size = regionSize - ( UINT32 ) partitions [ i ] . ptEntry . Offset ;
}
}
// Check for intersection with previous partition
if ( partitions [ i ] . ptEntry . Offset < previousPartitionEnd ) {
// Check if current partition is located inside previous one
if ( partitions [ i ] . ptEntry . Offset + partitions [ i ] . ptEntry . Size < = previousPartitionEnd ) {
msg ( usprintf ( " %s: BPDT partition is located inside another BPDT partition, skipped " , __FUNCTION__ ) ,
partitions [ i ] . index ) ;
partitions . erase ( partitions . begin ( ) + i ) ;
goto make_partition_table_consistent ;
}
else {
msg ( usprintf ( " %s: BPDT partition intersects with prevous one, skipped " , __FUNCTION__ ) ,
partitions [ i ] . index ) ;
partitions . erase ( partitions . begin ( ) + i ) ;
goto make_partition_table_consistent ;
}
}
// Check for padding between current and previous partitions
else if ( partitions [ i ] . ptEntry . Offset > previousPartitionEnd ) {
padding . ptEntry . Offset = previousPartitionEnd ;
padding . ptEntry . Size = partitions [ i ] . ptEntry . Offset - previousPartitionEnd ;
padding . type = Types : : Padding ;
std : : vector < BPDT_PARTITION_INFO > : : iterator iter = partitions . begin ( ) ;
std : : advance ( iter , i ) ;
partitions . insert ( iter , padding ) ;
}
}
// Partition map is consistent
for ( size_t i = 0 ; i < partitions . size ( ) ; i + + ) {
if ( partitions [ i ] . type = = Types : : BpdtPartition ) {
// Get info
UString name = bpdtEntryTypeToUString ( partitions [ i ] . ptEntry . Type ) ;
UByteArray partition = region . mid ( partitions [ i ] . ptEntry . Offset , partitions [ i ] . ptEntry . Size ) ;
UByteArray signature = partition . left ( sizeof ( UINT32 ) ) ;
UString info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh " ,
partition . size ( ) , partition . size ( ) ,
partitions [ i ] . ptEntry . Type ) +
UString ( " \n Split sub-partition first part: " ) + ( partitions [ i ] . ptEntry . SplitSubPartitionFirstPart ? " Yes " : " No " ) +
UString ( " \n Split sub-partition second part: " ) + ( partitions [ i ] . ptEntry . SplitSubPartitionSecondPart ? " Yes " : " No " ) +
UString ( " \n Code sub-partition: " ) + ( partitions [ i ] . ptEntry . CodeSubPartition ? " Yes " : " No " ) +
UString ( " \n UMA cachable: " ) + ( partitions [ i ] . ptEntry . UmaCachable ? " Yes " : " No " ) ;
UString text = bpdtEntryTypeToUString ( partitions [ i ] . ptEntry . Type ) ;
// Add tree item
UModelIndex partitionIndex = model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset , Types : : BpdtPartition , 0 , name , text , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
// Special case of S-BPDT
if ( partitions [ i ] . ptEntry . Type = = BPDT_ENTRY_TYPE_SBPDT ) {
UModelIndex sbpdtIndex ;
parseBpdtRegion ( partition , 0 , partitions [ i ] . ptEntry . Offset , partitionIndex , sbpdtIndex ) ; // Third parameter is a fixup for S-BPDT offset entries, because they are calculated from the start of BIOS region
}
// Parse code partitions
if ( readUnaligned ( ( const UINT32 * ) partition . constData ( ) ) = = CPD_SIGNATURE ) {
// Parse code partition contents
UModelIndex cpdIndex ;
parseCpdRegion ( partition , localOffset , partitionIndex , cpdIndex ) ;
}
if ( partitions [ i ] . ptEntry . Type > BPDT_LAST_KNOWN_ENTRY_TYPE ) {
msg ( usprintf ( " %s: BPDT entry of unknown type found " , __FUNCTION__ ) , partitionIndex ) ;
}
}
else if ( partitions [ i ] . type = = Types : : Padding ) {
UByteArray partition = region . mid ( partitions [ i ] . ptEntry . Offset , partitions [ i ] . ptEntry . Size ) ;
// Get info
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " ,
partition . size ( ) , partition . size ( ) ) ;
// Add tree item
model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset , Types : : Padding , getPaddingType ( partition ) , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
}
}
// Add padding after the last region
if ( ( UINT64 ) partitions . back ( ) . ptEntry . Offset + ( UINT64 ) partitions . back ( ) . ptEntry . Size < regionSize ) {
UByteArray partition = region . mid ( partitions . back ( ) . ptEntry . Offset + partitions . back ( ) . ptEntry . Size , regionSize - padding . ptEntry . Offset ) ;
// Get info
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " ,
partition . size ( ) , partition . size ( ) ) ;
// Add tree item
model - > addItem ( localOffset + partitions . back ( ) . ptEntry . Offset + partitions . back ( ) . ptEntry . Size , Types : : Padding , getPaddingType ( partition ) , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
}
return U_SUCCESS ;
}
USTATUS FfsParser : : parseCpdRegion ( const UByteArray & region , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
{
// Check directory size
if ( ( UINT32 ) region . size ( ) < sizeof ( CPD_REV1_HEADER ) ) {
msg ( usprintf ( " %s: CPD too small to fit rev1 partition table header " , __FUNCTION__ ) , parent ) ;
return U_INVALID_ME_PARTITION_TABLE ;
}
// Populate partition table header
const CPD_REV1_HEADER * cpdHeader = ( const CPD_REV1_HEADER * ) region . constData ( ) ;
// Check header version to be known
UINT32 ptHeaderSize = 0 ;
if ( cpdHeader - > HeaderVersion = = 2 ) {
if ( ( UINT32 ) region . size ( ) < sizeof ( CPD_REV2_HEADER ) ) {
msg ( usprintf ( " %s: CPD too small to fit rev2 partition table header " , __FUNCTION__ ) , parent ) ;
return U_INVALID_ME_PARTITION_TABLE ;
}
ptHeaderSize = sizeof ( CPD_REV2_HEADER ) ;
}
else if ( cpdHeader - > HeaderVersion = = 1 ) {
ptHeaderSize = sizeof ( CPD_REV1_HEADER ) ;
}
// Check directory size again
UINT32 ptBodySize = cpdHeader - > NumEntries * sizeof ( CPD_ENTRY ) ;
UINT32 ptSize = ptHeaderSize + ptBodySize ;
if ( ( UINT32 ) region . size ( ) < ptSize ) {
msg ( usprintf ( " %s: CPD too small to fit the whole partition table " , __FUNCTION__ ) , parent ) ;
return U_INVALID_ME_PARTITION_TABLE ;
}
// Get info
UByteArray header = region . left ( ptHeaderSize ) ;
UByteArray body = region . mid ( ptHeaderSize ) ;
UString name = usprintf ( " CPD partition table " ) ;
UString info = usprintf ( " Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Number of entries: %u \n "
" Header version: %02X \n Entry version: %02X " ,
region . size ( ) , region . size ( ) ,
header . size ( ) , header . size ( ) ,
body . size ( ) , body . size ( ) ,
cpdHeader - > NumEntries ,
cpdHeader - > HeaderVersion ,
cpdHeader - > EntryVersion ) ;
// Add tree item
index = model - > addItem ( localOffset , Types : : CpdStore , 0 , name , UString ( ) , info , header , body , UByteArray ( ) , Fixed , parent ) ;
// Add partition table entries
std : : vector < CPD_PARTITION_INFO > partitions ;
UINT32 offset = ptHeaderSize ;
const CPD_ENTRY * firstCpdEntry = ( const CPD_ENTRY * ) ( body . constData ( ) ) ;
for ( UINT32 i = 0 ; i < cpdHeader - > NumEntries ; i + + ) {
// Populate entry header
const CPD_ENTRY * cpdEntry = firstCpdEntry + i ;
UByteArray entry ( ( const char * ) cpdEntry , sizeof ( CPD_ENTRY ) ) ;
// Get info
name = usprintf ( " %c%c%c%c%c%c%c%c%c%c%c%c " ,
cpdEntry - > EntryName [ 0 ] , cpdEntry - > EntryName [ 1 ] , cpdEntry - > EntryName [ 2 ] , cpdEntry - > EntryName [ 3 ] ,
cpdEntry - > EntryName [ 4 ] , cpdEntry - > EntryName [ 5 ] , cpdEntry - > EntryName [ 6 ] , cpdEntry - > EntryName [ 7 ] ,
cpdEntry - > EntryName [ 8 ] , cpdEntry - > EntryName [ 9 ] , cpdEntry - > EntryName [ 10 ] , cpdEntry - > EntryName [ 11 ] ) ;
info = usprintf ( " Full size: %Xh (%u) \n Entry offset: %Xh \n Entry length: %Xh \n Huffman compressed: " ,
entry . size ( ) , entry . size ( ) ,
cpdEntry - > Offset . Offset ,
cpdEntry - > Length )
+ ( cpdEntry - > Offset . HuffmanCompressed ? " Yes " : " No " ) ;
// Add tree item
UModelIndex entryIndex = model - > addItem ( offset , Types : : CpdEntry , 0 , name , UString ( ) , info , UByteArray ( ) , entry , UByteArray ( ) , Fixed , index ) ;
// Adjust offset
offset + = sizeof ( CPD_ENTRY ) ;
if ( cpdEntry - > Offset . Offset ! = 0 & & cpdEntry - > Length ! = 0 ) {
// Add to partitions vector
CPD_PARTITION_INFO partition ;
partition . type = Types : : CpdPartition ;
partition . ptEntry = * cpdEntry ;
partition . index = entryIndex ;
partitions . push_back ( partition ) ;
}
}
// Add padding if there's no partions to add
if ( partitions . size ( ) = = 0 ) {
UByteArray partition = region . mid ( ptSize ) ;
// Get info
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " ,
partition . size ( ) , partition . size ( ) ) ;
// Add tree item
model - > addItem ( localOffset + ptSize , Types : : Padding , getPaddingType ( partition ) , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
return U_SUCCESS ;
}
// Sort partitions by offset
std : : sort ( partitions . begin ( ) , partitions . end ( ) ) ;
// Because lenghts for all Huffmann-compressed partitions mean nothing at all, we need to split all partitions into 2 classes:
// 1. CPD manifest (should be the first)
// 2. Metadata entries (should begin right after partition manifest and end before any code partition)
UINT32 i = 1 ;
while ( i < partitions . size ( ) ) {
name = usprintf ( " %c%c%c%c%c%c%c%c%c%c%c%c " ,
partitions [ i ] . ptEntry . EntryName [ 0 ] , partitions [ i ] . ptEntry . EntryName [ 1 ] , partitions [ i ] . ptEntry . EntryName [ 2 ] , partitions [ i ] . ptEntry . EntryName [ 3 ] ,
partitions [ i ] . ptEntry . EntryName [ 4 ] , partitions [ i ] . ptEntry . EntryName [ 5 ] , partitions [ i ] . ptEntry . EntryName [ 6 ] , partitions [ i ] . ptEntry . EntryName [ 7 ] ,
partitions [ i ] . ptEntry . EntryName [ 8 ] , partitions [ i ] . ptEntry . EntryName [ 9 ] , partitions [ i ] . ptEntry . EntryName [ 10 ] , partitions [ i ] . ptEntry . EntryName [ 11 ] ) ;
// Check if the current entry is metadata entry
if ( ! name . contains ( " .met " ) ) {
// No need to parse further, all metadata partitions are parsed
break ;
}
// Parse into data block, find Module Attributes extension, and get compressed size from there
UINT32 offset = 0 ;
UINT32 length = 0xFFFFFFFF ; // Special guardian value
UByteArray partition = region . mid ( partitions [ i ] . ptEntry . Offset . Offset , partitions [ i ] . ptEntry . Length ) ;
while ( offset < ( UINT32 ) partition . size ( ) ) {
const CPD_EXTENTION_HEADER * extHeader = ( const CPD_EXTENTION_HEADER * ) ( partition . constData ( ) + offset ) ;
if ( extHeader - > Length < = ( ( UINT32 ) partition . size ( ) - offset ) ) {
if ( extHeader - > Type = = CPD_EXT_TYPE_MODULE_ATTRIBUTES ) {
const CPD_EXT_MODULE_ATTRIBUTES * attrHeader = ( const CPD_EXT_MODULE_ATTRIBUTES * ) ( partition . constData ( ) + offset ) ;
length = attrHeader - > CompressedSize ;
}
offset + = extHeader - > Length ;
}
else break ;
}
// Search down for corresponding code partition
// Construct it's name by replacing last 4 non-zero butes of the name with zeros
UINT32 j = 0 ;
for ( UINT32 k = 11 ; k > 0 & & j < 4 ; k - - ) {
if ( name [ k ] ! = ' \x00 ' ) {
name [ k ] = ' \x00 ' ;
j + + ;
}
}
// Search
j = i + 1 ;
while ( j < partitions . size ( ) ) {
if ( name = = usprintf ( " %c%c%c%c%c%c%c%c%c%c%c%c " ,
partitions [ j ] . ptEntry . EntryName [ 0 ] , partitions [ j ] . ptEntry . EntryName [ 1 ] , partitions [ j ] . ptEntry . EntryName [ 2 ] , partitions [ j ] . ptEntry . EntryName [ 3 ] ,
partitions [ j ] . ptEntry . EntryName [ 4 ] , partitions [ j ] . ptEntry . EntryName [ 5 ] , partitions [ j ] . ptEntry . EntryName [ 6 ] , partitions [ j ] . ptEntry . EntryName [ 7 ] ,
partitions [ j ] . ptEntry . EntryName [ 8 ] , partitions [ j ] . ptEntry . EntryName [ 9 ] , partitions [ j ] . ptEntry . EntryName [ 10 ] , partitions [ j ] . ptEntry . EntryName [ 11 ] ) ) {
// Found it, update it's Length if needed
if ( partitions [ j ] . ptEntry . Offset . HuffmanCompressed ) {
partitions [ j ] . ptEntry . Length = length ;
}
else if ( length ! = 0xFFFFFFFF & & partitions [ j ] . ptEntry . Length ! = length ) {
msg ( usprintf ( " %s: partition size mismatch between partition table (%Xh) and partition metadata (%Xh) " , __FUNCTION__ ,
partitions [ j ] . ptEntry . Length , length ) , partitions [ j ] . index ) ;
partitions [ j ] . ptEntry . Length = length ; // Believe metadata
}
// No need to search further
break ;
}
// Check the next partition
j + + ;
}
// Check the next partition
i + + ;
}
make_partition_table_consistent :
// Sort partitions by offset
std : : sort ( partitions . begin ( ) , partitions . end ( ) ) ;
// Check for intersections and paddings between partitions
CPD_PARTITION_INFO padding ;
// Check intersection with the partition table header
if ( partitions . front ( ) . ptEntry . Offset . Offset < ptSize ) {
msg ( usprintf ( " %s: CPD partition has intersection with CPD partition table, skipped " , __FUNCTION__ ) ,
partitions . front ( ) . index ) ;
partitions . erase ( partitions . begin ( ) ) ;
goto make_partition_table_consistent ;
}
// Check for padding between partition table and the first partition
else if ( partitions . front ( ) . ptEntry . Offset . Offset > ptSize ) {
padding . ptEntry . Offset . Offset = ptSize ;
padding . ptEntry . Length = partitions . front ( ) . ptEntry . Offset . Offset - padding . ptEntry . Offset . Offset ;
padding . type = Types : : Padding ;
partitions . insert ( partitions . begin ( ) , padding ) ;
}
// Check for intersections/paddings between partitions
for ( size_t i = 1 ; i < partitions . size ( ) ; i + + ) {
UINT32 previousPartitionEnd = partitions [ i - 1 ] . ptEntry . Offset . Offset + partitions [ i - 1 ] . ptEntry . Length ;
// Check that current region is fully present in the image
if ( ( UINT64 ) partitions [ i ] . ptEntry . Offset . Offset + ( UINT64 ) partitions [ i ] . ptEntry . Length > ( UINT64 ) region . size ( ) ) {
if ( ( UINT64 ) partitions [ i ] . ptEntry . Offset . Offset > = ( UINT64 ) region . size ( ) ) {
msg ( usprintf ( " %s: CPD partition is located outside of the opened image, skipped " , __FUNCTION__ ) , partitions [ i ] . index ) ;
partitions . erase ( partitions . begin ( ) + i ) ;
goto make_partition_table_consistent ;
}
else {
msg ( usprintf ( " %s: CPD partition can't fit into it's region, truncated " , __FUNCTION__ ) , partitions [ i ] . index ) ;
partitions [ i ] . ptEntry . Length = ( UINT32 ) region . size ( ) - ( UINT32 ) partitions [ i ] . ptEntry . Offset . Offset ;
}
}
// Check for intersection with previous partition
if ( partitions [ i ] . ptEntry . Offset . Offset < previousPartitionEnd ) {
// Check if current partition is located inside previous one
if ( partitions [ i ] . ptEntry . Offset . Offset + partitions [ i ] . ptEntry . Length < = previousPartitionEnd ) {
msg ( usprintf ( " %s: CPD partition is located inside another CPD partition, skipped " , __FUNCTION__ ) ,
partitions [ i ] . index ) ;
partitions . erase ( partitions . begin ( ) + i ) ;
goto make_partition_table_consistent ;
}
else {
msg ( usprintf ( " %s: CPD partition intersects with previous one, skipped " , __FUNCTION__ ) ,
partitions [ i ] . index ) ;
partitions . erase ( partitions . begin ( ) + i ) ;
goto make_partition_table_consistent ;
}
}
// Check for padding between current and previous partitions
else if ( partitions [ i ] . ptEntry . Offset . Offset > previousPartitionEnd ) {
padding . ptEntry . Offset . Offset = previousPartitionEnd ;
padding . ptEntry . Length = partitions [ i ] . ptEntry . Offset . Offset - previousPartitionEnd ;
padding . type = Types : : Padding ;
std : : vector < CPD_PARTITION_INFO > : : iterator iter = partitions . begin ( ) ;
std : : advance ( iter , i ) ;
partitions . insert ( iter , padding ) ;
}
}
// Check for padding after the last region
if ( ( UINT64 ) partitions . back ( ) . ptEntry . Offset . Offset + ( UINT64 ) partitions . back ( ) . ptEntry . Length < ( UINT64 ) region . size ( ) ) {
padding . ptEntry . Offset . Offset = partitions . back ( ) . ptEntry . Offset . Offset + partitions . back ( ) . ptEntry . Length ;
padding . ptEntry . Length = ( UINT32 ) region . size ( ) - padding . ptEntry . Offset . Offset ;
padding . type = Types : : Padding ;
partitions . push_back ( padding ) ;
}
// Partition map is consistent
for ( size_t i = 0 ; i < partitions . size ( ) ; i + + ) {
if ( partitions [ i ] . type = = Types : : CpdPartition ) {
UByteArray partition = region . mid ( partitions [ i ] . ptEntry . Offset . Offset , partitions [ i ] . ptEntry . Length ) ;
// Get info
name = usprintf ( " %c%c%c%c%c%c%c%c%c%c%c%c " ,
partitions [ i ] . ptEntry . EntryName [ 0 ] , partitions [ i ] . ptEntry . EntryName [ 1 ] , partitions [ i ] . ptEntry . EntryName [ 2 ] , partitions [ i ] . ptEntry . EntryName [ 3 ] ,
partitions [ i ] . ptEntry . EntryName [ 4 ] , partitions [ i ] . ptEntry . EntryName [ 5 ] , partitions [ i ] . ptEntry . EntryName [ 6 ] , partitions [ i ] . ptEntry . EntryName [ 7 ] ,
partitions [ i ] . ptEntry . EntryName [ 8 ] , partitions [ i ] . ptEntry . EntryName [ 9 ] , partitions [ i ] . ptEntry . EntryName [ 10 ] , partitions [ i ] . ptEntry . EntryName [ 11 ] ) ;
// It's a manifest
if ( name . contains ( " .man " ) ) {
if ( ! partitions [ i ] . ptEntry . Offset . HuffmanCompressed
& & partitions [ i ] . ptEntry . Length > = sizeof ( CPD_MANIFEST_HEADER ) ) {
const CPD_MANIFEST_HEADER * manifestHeader = ( const CPD_MANIFEST_HEADER * ) partition . constData ( ) ;
if ( manifestHeader - > HeaderId = = ME_MANIFEST_HEADER_ID ) {
UByteArray header = partition . left ( manifestHeader - > HeaderLength * sizeof ( UINT32 ) ) ;
UByteArray body = partition . mid ( header . size ( ) ) ;
info + = usprintf (
" \n Header type: %u \n Header length: %Xh (%u) \n Header version: %Xh \n Flags: %08Xh \n Vendor: %Xh \n "
" Date: %Xh \n Size: %Xh (%u) \n Version: %u.%u.%u.%u \n Security version number: %u \n Modulus size: %Xh (%u) \n Exponent size: %Xh (%u) " ,
manifestHeader - > HeaderType ,
manifestHeader - > HeaderLength * sizeof ( UINT32 ) , manifestHeader - > HeaderLength * sizeof ( UINT32 ) ,
manifestHeader - > HeaderVersion ,
manifestHeader - > Flags ,
manifestHeader - > Vendor ,
manifestHeader - > Date ,
manifestHeader - > Size * sizeof ( UINT32 ) , manifestHeader - > Size * sizeof ( UINT32 ) ,
manifestHeader - > VersionMajor , manifestHeader - > VersionMinor , manifestHeader - > VersionBugfix , manifestHeader - > VersionBuild ,
manifestHeader - > SecurityVersion ,
manifestHeader - > ModulusSize * sizeof ( UINT32 ) , manifestHeader - > ModulusSize * sizeof ( UINT32 ) ,
manifestHeader - > ExponentSize * sizeof ( UINT32 ) , manifestHeader - > ExponentSize * sizeof ( UINT32 ) ) ;
// Add tree item
UModelIndex partitionIndex = model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset . Offset , Types : : CpdPartition , Subtypes : : ManifestCpdPartition , name , UString ( ) , info , header , body , UByteArray ( ) , Fixed , parent ) ;
// Parse data as extensions area
parseCpdExtensionsArea ( partitionIndex ) ;
}
}
}
// It's a metadata
else if ( name . contains ( " .met " ) ) {
info = usprintf ( " Full size: %Xh (%u) \n Entry offset: %Xh \n Entry length: %Xh \n Huffman compressed: " ,
partition . size ( ) , partition . size ( ) ,
partitions [ i ] . ptEntry . Offset . Offset ,
partitions [ i ] . ptEntry . Length )
+ ( partitions [ i ] . ptEntry . Offset . HuffmanCompressed ? " Yes " : " No " ) ;
// Calculate SHA256 hash over the metadata and add it to it's info
UByteArray hash ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
sha256 ( partition . constData ( ) , partition . size ( ) , hash . data ( ) ) ;
info + = UString ( " \n Metadata hash: " ) + UString ( hash . toHex ( ) . constData ( ) ) ;
// Add three item
UModelIndex partitionIndex = model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset . Offset , Types : : CpdPartition , Subtypes : : MetadataCpdPartition , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
// Parse data as extensions area
parseCpdExtensionsArea ( partitionIndex ) ;
}
// It's a key
else if ( name . contains ( " .key " ) ) {
info = usprintf ( " Full size: %Xh (%u) \n Entry offset: %Xh \n Entry length: %Xh \n Huffman compressed: " ,
partition . size ( ) , partition . size ( ) ,
partitions [ i ] . ptEntry . Offset . Offset ,
partitions [ i ] . ptEntry . Length )
+ ( partitions [ i ] . ptEntry . Offset . HuffmanCompressed ? " Yes " : " No " ) ;
// Calculate SHA256 hash over the key and add it to it's info
UByteArray hash ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
sha256 ( partition . constData ( ) , partition . size ( ) , hash . data ( ) ) ;
info + = UString ( " \n Hash: " ) + UString ( hash . toHex ( ) . constData ( ) ) ;
// Add three item
UModelIndex partitionIndex = model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset . Offset , Types : : CpdPartition , Subtypes : : KeyCpdPartition , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
// Parse data as extensions area
parseCpdExtensionsArea ( partitionIndex ) ;
}
// It's a code
else {
info = usprintf ( " Full size: %Xh (%u) \n Entry offset: %Xh \n Entry length: %Xh \n Huffman compressed: " ,
partition . size ( ) , partition . size ( ) ,
partitions [ i ] . ptEntry . Offset . Offset ,
partitions [ i ] . ptEntry . Length )
+ ( partitions [ i ] . ptEntry . Offset . HuffmanCompressed ? " Yes " : " No " ) ;
// Calculate SHA256 hash over the code and add it to it's info
UByteArray hash ( SHA256_DIGEST_SIZE , ' \x00 ' ) ;
sha256 ( partition . constData ( ) , partition . size ( ) , hash . data ( ) ) ;
info + = UString ( " \n Hash: " ) + UString ( hash . toHex ( ) . constData ( ) ) ;
UModelIndex codeIndex = model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset . Offset , Types : : CpdPartition , Subtypes : : CodeCpdPartition , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
parseRawArea ( codeIndex ) ;
}
}
else if ( partitions [ i ] . type = = Types : : Padding ) {
UByteArray partition = region . mid ( partitions [ i ] . ptEntry . Offset . Offset , partitions [ i ] . ptEntry . Length ) ;
// Get info
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " , partition . size ( ) , partition . size ( ) ) ;
// Add tree item
model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset . Offset , Types : : Padding , getPaddingType ( partition ) , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
}
else {
msg ( usprintf ( " %s: CPD partition of unknown type found " , __FUNCTION__ ) , parent ) ;
return U_INVALID_ME_PARTITION_TABLE ;
}
}
return U_SUCCESS ;
}
USTATUS FfsParser : : parseCpdExtensionsArea ( const UModelIndex & index )
{
if ( ! index . isValid ( ) ) {
return U_INVALID_PARAMETER ;
}
UByteArray body = model - > body ( index ) ;
UINT32 offset = 0 ;
while ( offset < ( UINT32 ) body . size ( ) ) {
const CPD_EXTENTION_HEADER * extHeader = ( const CPD_EXTENTION_HEADER * ) ( body . constData ( ) + offset ) ;
if ( extHeader - > Length < = ( ( UINT32 ) body . size ( ) - offset ) ) {
UByteArray partition = body . mid ( offset , extHeader - > Length ) ;
UString name = cpdExtensionTypeToUstring ( extHeader - > Type ) ;
UString info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh " , partition . size ( ) , partition . size ( ) , extHeader - > Type ) ;
// Parse Signed Package Info a bit further
UModelIndex extIndex ;
if ( extHeader - > Type = = CPD_EXT_TYPE_SIGNED_PACKAGE_INFO ) {
UByteArray header = partition . left ( sizeof ( CPD_EXT_SIGNED_PACKAGE_INFO ) ) ;
UByteArray data = partition . mid ( header . size ( ) ) ;
const CPD_EXT_SIGNED_PACKAGE_INFO * infoHeader = ( const CPD_EXT_SIGNED_PACKAGE_INFO * ) header . constData ( ) ;
info = usprintf ( " Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Type: %Xh \n "
" Package name: %c%c%c%c \n Version control number: %Xh \n Security version number: %Xh \n "
" Usage bitmap: %02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X " ,
partition . size ( ) , partition . size ( ) ,
header . size ( ) , header . size ( ) ,
body . size ( ) , body . size ( ) ,
infoHeader - > ExtensionType ,
infoHeader - > PackageName [ 0 ] , infoHeader - > PackageName [ 1 ] , infoHeader - > PackageName [ 2 ] , infoHeader - > PackageName [ 3 ] ,
infoHeader - > Vcn ,
infoHeader - > Svn ,
infoHeader - > UsageBitmap [ 0 ] , infoHeader - > UsageBitmap [ 1 ] , infoHeader - > UsageBitmap [ 2 ] , infoHeader - > UsageBitmap [ 3 ] ,
infoHeader - > UsageBitmap [ 4 ] , infoHeader - > UsageBitmap [ 5 ] , infoHeader - > UsageBitmap [ 6 ] , infoHeader - > UsageBitmap [ 7 ] ,
infoHeader - > UsageBitmap [ 8 ] , infoHeader - > UsageBitmap [ 9 ] , infoHeader - > UsageBitmap [ 10 ] , infoHeader - > UsageBitmap [ 11 ] ,
infoHeader - > UsageBitmap [ 12 ] , infoHeader - > UsageBitmap [ 13 ] , infoHeader - > UsageBitmap [ 14 ] , infoHeader - > UsageBitmap [ 15 ] ) ;
// Add tree item
extIndex = model - > addItem ( offset , Types : : CpdExtension , 0 , name , UString ( ) , info , header , data , UByteArray ( ) , Fixed , index ) ;
parseSignedPackageInfoData ( extIndex ) ;
}
// Parse IFWI Partition Manifest a bit further
else if ( extHeader - > Type = = CPD_EXT_TYPE_IFWI_PARTITION_MANIFEST ) {
const CPD_EXT_IFWI_PARTITION_MANIFEST * attrHeader = ( const CPD_EXT_IFWI_PARTITION_MANIFEST * ) partition . constData ( ) ;
// This hash is stored reversed
// Need to reverse it back to normal
UByteArray hash ( ( const char * ) & attrHeader - > CompletePartitionHash , sizeof ( attrHeader - > CompletePartitionHash ) ) ;
std : : reverse ( hash . begin ( ) , hash . end ( ) ) ;
info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh \n "
" Partition name: %c%c%c%c \n Partition length: %Xh \n Partition version major: %Xh \n Partition version minor: %Xh \n "
" Data format version: %Xh \n Instance ID: %Xh \n Hash algorithm: %Xh \n Hash size: %Xh \n Action on update: %Xh " ,
partition . size ( ) , partition . size ( ) ,
attrHeader - > ExtensionType ,
attrHeader - > PartitionName [ 0 ] , attrHeader - > PartitionName [ 1 ] , attrHeader - > PartitionName [ 2 ] , attrHeader - > PartitionName [ 3 ] ,
attrHeader - > CompletePartitionLength ,
attrHeader - > PartitionVersionMajor , attrHeader - > PartitionVersionMinor ,
attrHeader - > DataFormatVersion ,
attrHeader - > InstanceId ,
attrHeader - > HashAlgorithm ,
attrHeader - > HashSize ,
attrHeader - > ActionOnUpdate )
+ UString ( " \n Support multiple instances: " ) + ( attrHeader - > SupportMultipleInstances ? " Yes " : " No " )
+ UString ( " \n Support API version based update: " ) + ( attrHeader - > SupportApiVersionBasedUpdate ? " Yes " : " No " )
+ UString ( " \n Obey full update rules: " ) + ( attrHeader - > ObeyFullUpdateRules ? " Yes " : " No " )
+ UString ( " \n IFR enable only: " ) + ( attrHeader - > IfrEnableOnly ? " Yes " : " No " )
+ UString ( " \n Allow cross point update: " ) + ( attrHeader - > AllowCrossPointUpdate ? " Yes " : " No " )
+ UString ( " \n Allow cross hotfix update: " ) + ( attrHeader - > AllowCrossHotfixUpdate ? " Yes " : " No " )
+ UString ( " \n Partial update only: " ) + ( attrHeader - > PartialUpdateOnly ? " Yes " : " No " )
+ UString ( " \n Partition hash: " ) + UString ( hash . toHex ( ) . constData ( ) ) ;
// Add tree item
extIndex = model - > addItem ( offset , Types : : CpdExtension , 0 , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , index ) ;
}
// Parse Module Attributes a bit further
else if ( extHeader - > Type = = CPD_EXT_TYPE_MODULE_ATTRIBUTES ) {
const CPD_EXT_MODULE_ATTRIBUTES * attrHeader = ( const CPD_EXT_MODULE_ATTRIBUTES * ) partition . constData ( ) ;
// This hash is stored reversed
// Need to reverse it back to normal
UByteArray hash ( ( const char * ) & attrHeader - > ImageHash , sizeof ( attrHeader - > ImageHash ) ) ;
std : : reverse ( hash . begin ( ) , hash . end ( ) ) ;
info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh \n "
" Compression type: %Xh \n Uncompressed size: %Xh (%u) \n Compressed size: %Xh (%u) \n Global module ID: %Xh \n Image hash: " ,
partition . size ( ) , partition . size ( ) ,
attrHeader - > ExtensionType ,
attrHeader - > CompressionType ,
attrHeader - > UncompressedSize , attrHeader - > UncompressedSize ,
attrHeader - > CompressedSize , attrHeader - > CompressedSize ,
attrHeader - > GlobalModuleId ) + UString ( hash . toHex ( ) . constData ( ) ) ;
// Add tree item
extIndex = model - > addItem ( offset , Types : : CpdExtension , 0 , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , index ) ;
}
// Parse everything else
else {
// Add tree item, if needed
extIndex = model - > addItem ( offset , Types : : CpdExtension , 0 , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , index ) ;
}
if ( extHeader - > Type > CPD_LAST_KNOWN_EXT_TYPE ) {
msg ( usprintf ( " %s: CPD extention of unknown type found " , __FUNCTION__ ) , extIndex ) ;
}
offset + = extHeader - > Length ;
}
else break ;
// TODO: add padding at the end
}
return U_SUCCESS ;
}
USTATUS FfsParser : : parseSignedPackageInfoData ( const UModelIndex & index )
{
if ( ! index . isValid ( ) ) {
return U_INVALID_PARAMETER ;
}
UByteArray body = model - > body ( index ) ;
UINT32 offset = 0 ;
while ( offset < ( UINT32 ) body . size ( ) ) {
const CPD_EXT_SIGNED_PACKAGE_INFO_MODULE * moduleHeader = ( const CPD_EXT_SIGNED_PACKAGE_INFO_MODULE * ) ( body . constData ( ) + offset ) ;
if ( sizeof ( CPD_EXT_SIGNED_PACKAGE_INFO_MODULE ) < = ( ( UINT32 ) body . size ( ) - offset ) ) {
UByteArray module ( ( const char * ) moduleHeader , sizeof ( CPD_EXT_SIGNED_PACKAGE_INFO_MODULE ) ) ;
UString name = usprintf ( " %c%c%c%c%c%c%c%c%c%c%c%c " ,
moduleHeader - > Name [ 0 ] , moduleHeader - > Name [ 1 ] , moduleHeader - > Name [ 2 ] , moduleHeader - > Name [ 3 ] ,
moduleHeader - > Name [ 4 ] , moduleHeader - > Name [ 5 ] , moduleHeader - > Name [ 6 ] , moduleHeader - > Name [ 7 ] ,
moduleHeader - > Name [ 8 ] , moduleHeader - > Name [ 9 ] , moduleHeader - > Name [ 10 ] , moduleHeader - > Name [ 11 ] ) ;
// This hash is stored reversed
// Need to reverse it back to normal
UByteArray hash ( ( const char * ) & moduleHeader - > MetadataHash , sizeof ( moduleHeader - > MetadataHash ) ) ;
std : : reverse ( hash . begin ( ) , hash . end ( ) ) ;
UString info = usprintf ( " Full size: %X (%u) \n Type: %Xh \n Hash algorithm: %Xh \n Hash size: %Xh (%u) \n Metadata size: %Xh (%u) \n Metadata hash: " ,
module . size ( ) , module . size ( ) ,
moduleHeader - > Type ,
moduleHeader - > HashAlgorithm ,
moduleHeader - > HashSize , moduleHeader - > HashSize ,
moduleHeader - > MetadataSize , moduleHeader - > MetadataSize ) + UString ( hash . toHex ( ) . constData ( ) ) ;
// Add tree otem
model - > addItem ( offset , Types : : CpdSpiEntry , 0 , name , UString ( ) , info , UByteArray ( ) , module , UByteArray ( ) , Fixed , index ) ;
offset + = module . size ( ) ;
}
else break ;
// TODO: add padding at the end
}
return U_SUCCESS ;
}