2016-07-09 16:08:32 +08:00
/* ffsparser.cpp
2022-08-28 18:47:01 +08:00
Copyright ( c ) 2018 , Nikolaj Schlej . All rights reserved .
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 .
*/
2015-03-13 14:48:53 +08:00
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>
2021-10-07 23:51:39 +08:00
# include <iostream>
2016-10-10 14:05:04 +08:00
# include "descriptor.h"
# include "ffs.h"
# include "gbe.h"
# include "me.h"
2022-08-29 14:23:38 +08:00
# include "intel_fit.h"
2016-10-10 14:05:04 +08:00
# include "nvram.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"
2022-08-29 14:23:38 +08:00
# include "fitparser.h"
# include "digest/sha1.h"
# include "digest/sha2.h"
# include "digest/sm3.h"
2017-12-11 09:56:00 +08:00
# ifndef QT_CORE_LIB
namespace Qt {
2022-08-28 18:47:01 +08:00
enum GlobalColor {
red = 7 ,
green = 8 ,
cyan = 10 ,
yellow = 12 ,
} ;
2017-12-11 09:56:00 +08:00
}
# 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 ;
2021-10-07 23:51:39 +08:00
bool hasMetaData ;
2019-08-20 02:36:02 +08:00
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 ) ,
2022-08-29 14:23:38 +08:00
imageBase ( 0 ) , addressDiff ( 0x100000000ULL ) , protectedRegionsBase ( 0 ) {
fitParser = new FitParser ( treeModel , this ) ;
2020-02-09 03:05:33 +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 ;
2022-08-29 14:23:38 +08:00
delete fitParser ;
2017-12-11 09:56:00 +08:00
}
2020-02-09 03:05:33 +08:00
// Obtain parser messages
2017-12-11 09:56:00 +08:00
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 ( ) ;
2022-08-29 14:23:38 +08:00
std : : vector < std : : pair < UString , UModelIndex > > fitVector = fitParser - > getMessages ( ) ;
2017-12-11 09:56:00 +08:00
std : : vector < std : : pair < UString , UModelIndex > > resultVector = messagesVector ;
resultVector . insert ( resultVector . end ( ) , meVector . begin ( ) , meVector . end ( ) ) ;
2022-08-29 14:23:38 +08:00
resultVector . insert ( resultVector . end ( ) , nvramVector . begin ( ) , nvramVector . end ( ) ) ; \
resultVector . insert ( resultVector . end ( ) , fitVector . begin ( ) , fitVector . end ( ) ) ;
2017-12-11 09:56:00 +08:00
return resultVector ;
}
2022-08-29 14:23:38 +08:00
// Obtain FIT table from FIT parser
std : : vector < std : : pair < std : : vector < UString > , UModelIndex > > FfsParser : : getFitTable ( ) const
{
return fitParser - > getFitTable ( ) ;
}
// Obtain security info from FIT parser
UString FfsParser : : getSecurityInfo ( ) const {
return securityInfo + fitParser - > getSecurityInfo ( ) ;
}
2016-02-02 09:08:08 +08:00
// Firmware image parsing functions
2020-02-09 03:05:33 +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 ;
2022-08-28 18:47:01 +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 ;
2022-08-29 14:23:38 +08:00
protectedRegionsBase = 0 ;
2018-10-08 17:58:12 +08:00
securityInfo = " " ;
2022-08-29 14:23:38 +08:00
protectedRanges . clear ( ) ;
lastVtf = UModelIndex ( ) ;
dxeCore = UModelIndex ( ) ;
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
// 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
}
2022-08-28 18:47:01 +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 ( ) ) {
2022-08-29 14:23:38 +08:00
return U_INVALID_PARAMETER ;
2018-04-30 13:33:19 +08:00
}
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
USTATUS result ;
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2018-04-30 13:33:19 +08:00
// Try parsing as Intel image
result = parseIntelImage ( buffer , 0 , UModelIndex ( ) , index ) ;
if ( result ! = U_ITEM_NOT_FOUND ) {
return result ;
}
2022-08-28 18:47:01 +08:00
2018-04-30 13:33:19 +08:00
// 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 " ) ;
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) buffer . size ( ) , ( UINT32 ) buffer . size ( ) ) ;
2018-04-30 13:33:19 +08:00
// 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 ) ;
2022-08-28 18:47:01 +08:00
2018-04-30 13:33:19 +08:00
// Parse the image as raw area
2022-08-29 14:23:38 +08:00
protectedRegionsBase = 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
}
2022-08-28 18:47:01 +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 ( ) ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ) +
2022-08-28 18:01:43 +08:00
usprintf ( " \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Image size: %Xh (%u) \n Flags: %08Xh " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) capsule . size ( ) , ( UINT32 ) capsule . size ( ) ,
2018-04-30 13:33:19 +08:00
capsuleHeaderSize , capsuleHeaderSize ,
capsuleHeader - > CapsuleImageSize - capsuleHeaderSize , capsuleHeader - > CapsuleImageSize - capsuleHeaderSize ,
capsuleHeader - > Flags ) ;
2022-08-28 18:47:01 +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 ( ) ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ) +
2022-08-28 18:01:43 +08:00
usprintf ( " \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Image size: %Xh (%u) \n Flags: %08Xh " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) capsule . size ( ) , ( UINT32 ) capsule . size ( ) ,
2018-04-30 13:33:19 +08:00
capsuleHeaderSize , capsuleHeaderSize ,
capsuleHeader - > FullSize - capsuleHeaderSize , capsuleHeader - > FullSize - capsuleHeaderSize ,
capsuleHeader - > Flags ) ;
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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 ( ) ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ) +
2022-08-28 18:01:43 +08:00
usprintf ( " \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Image size: %Xh (%u) \n Flags: %08Xh " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) capsule . size ( ) , ( UINT32 ) capsule . size ( ) ,
2018-04-30 13:33:19 +08:00
capsuleHeaderSize , capsuleHeaderSize ,
capsuleHeader - > CapsuleHeader . CapsuleImageSize - capsuleHeaderSize , capsuleHeader - > CapsuleHeader . CapsuleImageSize - capsuleHeaderSize ,
capsuleHeader - > CapsuleHeader . Flags ) ;
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
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
}
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +08:00
2018-04-30 13:33:19 +08:00
// Parse as generic image
return parseGenericImage ( image , capsuleHeaderSize , index , imageIndex ) ;
}
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
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 ( ) ;
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2016-02-02 09:08:08 +08:00
// Regions
2016-03-01 15:20:44 +08:00
std : : vector < REGION_INFO > regions ;
2022-08-28 18:47:01 +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 ) ;
2022-11-05 18:03:50 +08:00
if ( ( UINT32 ) intelImage . size ( ) < me . offset + me . length ) {
2022-10-15 14:20:55 +08:00
msg ( usprintf ( " %s: " , __FUNCTION__ )
+ itemSubtypeToUString ( Types : : Region , me . type )
+ UString ( " region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image " ) ,
index ) ;
return U_TRUNCATED_IMAGE ;
}
2016-02-02 09:08:08 +08:00
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
}
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
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 ;
2015-10-05 16:21:33 +08:00
}
2022-10-15 14:20:55 +08:00
2022-11-05 18:03:50 +08:00
if ( ( UINT32 ) intelImage . size ( ) < bios . offset + bios . length ) {
2022-10-15 14:20:55 +08:00
msg ( usprintf ( " %s: " , __FUNCTION__ )
+ itemSubtypeToUString ( Types : : Region , bios . type )
+ UString ( " region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image " ) ,
index ) ;
return U_TRUNCATED_IMAGE ;
2015-03-13 14:48:53 +08:00
}
2022-10-15 14:20:55 +08:00
bios . data = intelImage . mid ( bios . offset , bios . length ) ;
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
}
2022-08-28 18:47:01 +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
2022-08-28 18:47:01 +08:00
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 ) {
2022-11-05 18:03:50 +08:00
if ( ( UINT32 ) intelImage . size ( ) < region . offset + region . length ) {
2022-10-15 14:20:55 +08:00
msg ( usprintf ( " %s: " , __FUNCTION__ )
+ itemSubtypeToUString ( Types : : Region , region . type )
+ UString ( " region is located outside of the opened image. If your system uses dual-chip storage, please append another part to the opened image " ) ,
index ) ;
return U_TRUNCATED_IMAGE ;
}
2017-12-11 09:56:00 +08:00
region . data = intelImage . mid ( region . offset , region . length ) ;
regions . push_back ( region ) ;
}
2015-09-13 04:53:07 +08:00
}
}
2022-08-28 18:47:01 +08:00
2022-09-13 15:45:40 +08:00
// Regions can not be empty here
if ( regions . empty ( ) ) {
msg ( usprintf ( " %s: descriptor parsing failed, no regions found " , __FUNCTION__ ) ) ;
return U_INVALID_FLASH_DESCRIPTOR ;
}
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 ( ) ) ;
2022-08-28 18:47:01 +08:00
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 ) {
2022-10-15 14:20:55 +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
}
2020-02-09 03:05:33 +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 for intersection with previous region
if ( regions [ i ] . offset < previousRegionEnd ) {
2022-10-15 14:20:55 +08:00
msg ( usprintf ( " %s: " , __FUNCTION__ )
+ itemSubtypeToUString ( Types : : Region , regions [ i ] . type )
+ UString ( " region has intersection with " ) + itemSubtypeToUString ( Types : : Region , regions [ i - 1 ] . type )
+ UString ( " region " ) ,
2016-06-26 11:54:21 +08:00
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 ;
2021-04-04 17:09:23 +08:00
region . length = ( UINT32 ) ( intelImage . size ( ) - region . offset ) ;
2016-02-02 09:08:08 +08:00
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
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Region map is consistent
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Intel image
2016-06-26 11:54:21 +08:00
UString name ( " Intel image " ) ;
2022-08-28 18:01:43 +08:00
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 " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) intelImage . size ( ) , ( UINT32 ) intelImage . size ( ) ,
descriptorMap - > NumberOfFlashChips + 1 , //
descriptorMap - > NumberOfRegions + 1 , // Zero-based numbers in storage
descriptorMap - > NumberOfMasters + 1 , //
descriptorMap - > NumberOfPchStraps ,
descriptorMap - > NumberOfProcStraps ) ;
2018-10-08 17:58:12 +08:00
// Set image base
2019-01-07 21:05:57 +08:00
imageBase = model - > base ( parent ) + localOffset ;
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:47:01 +08:00
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 )
2022-08-29 14:23:38 +08:00
info + = " \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
}
2022-08-28 18:47:01 +08:00
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 " ,
2022-08-28 18:47:01 +08:00
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: " )
2022-08-28 18:47:01 +08:00
+ 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 " ) ;
2016-06-26 11:54:21 +08:00
info + = UString ( " \n BIOS Yes Yes " )
2022-08-28 18:47:01 +08:00
+ usprintf ( " \n ME %s %s " , masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ) ;
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n GbE %s %s " , masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ,
2022-08-28 18:47:01 +08:00
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ) ;
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n PDR %s %s " , masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " ,
2022-08-28 18:47:01 +08:00
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 " ,
2022-08-28 18:47:01 +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: " )
2022-08-28 18:47:01 +08:00
+ 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 " ) ;
2016-06-26 11:54:21 +08:00
info + = UString ( " \n BIOS Yes Yes " )
2022-08-28 18:47:01 +08:00
+ usprintf ( " \n ME %s %s " ,
masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_ME ? " Yes " : " No " ) ;
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n GbE %s %s " ,
2022-08-28 18:47:01 +08:00
masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_GBE ? " Yes " : " No " ) ;
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n PDR %s %s " ,
2022-08-28 18:47:01 +08:00
masterSection - > BiosRead & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " ,
masterSection - > BiosWrite & FLASH_DESCRIPTOR_REGION_ACCESS_PDR ? " Yes " : " No " ) ;
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n EC %s %s " ,
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 )
2022-08-28 18:47:01 +08:00
+ jedecId
+ UString ( " ) " ) ;
2022-08-29 14:23:38 +08:00
if ( jedecId . startsWith ( " 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 + + ;
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// 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 ) ;
2022-08-28 18:47:01 +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 ) {
2022-08-28 18:47:01 +08:00
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 ;
case Subtypes : : DevExp1Region :
result = parseDevExp1Region ( region . data , region . offset , index , regionIndex ) ;
break ;
case Subtypes : : Bios2Region :
case Subtypes : : MicrocodeRegion :
case Subtypes : : EcRegion :
case Subtypes : : DevExp2Region :
case Subtypes : : IeRegion :
case Subtypes : : Tgbe1Region :
case Subtypes : : Tgbe2Region :
case Subtypes : : Reserved1Region :
case Subtypes : : Reserved2Region :
case Subtypes : : PttRegion :
result = parseGenericRegion ( region . type , region . data , region . offset , index , regionIndex ) ;
break ;
case Subtypes : : ZeroPadding :
case Subtypes : : OnePadding :
case Subtypes : : DataPadding : {
// Add padding between regions
UByteArray padding = intelImage . mid ( region . offset , region . length ) ;
// Get info
name = UString ( " Padding " ) ;
info = usprintf ( " Full size: %Xh (%u) " ,
( UINT32 ) padding . size ( ) , ( UINT32 ) padding . size ( ) ) ;
// Add tree item
regionIndex = model - > addItem ( region . offset , Types : : Padding , getPaddingType ( padding ) , name , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
result = U_SUCCESS ;
2016-02-02 09:08:08 +08:00
} break ;
2022-08-28 18:47:01 +08:00
default :
msg ( usprintf ( " %s: region of unknown type found " , __FUNCTION__ ) , index ) ;
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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:01:43 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n MAC: %02X:%02X:%02X:%02X:%02X:%02X \n Version: %u.%u " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) gbe . size ( ) , ( UINT32 ) 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 ) ;
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name ( " ME region " ) ;
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) me . size ( ) , ( UINT32 ) 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
2022-08-29 14:23:38 +08:00
UINT32 sig2Value = ME_VERSION_SIGNATURE2 ;
UByteArray sig2 ( ( const char * ) & sig2Value , sizeof ( sig2Value ) ) ;
INT32 versionOffset = ( INT32 ) me . indexOf ( sig2 ) ;
if ( versionOffset < 0 ) { // New signature not found
2015-03-13 14:48:53 +08:00
// Search for old signature
2022-08-29 14:23:38 +08:00
UINT32 sigValue = ME_VERSION_SIGNATURE ;
UByteArray sig ( ( const char * ) & sigValue , sizeof ( sigValue ) ) ;
versionOffset = ( INT32 ) me . indexOf ( sig ) ;
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 ;
}
}
2022-08-28 18:47:01 +08:00
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 ;
2022-08-28 18:47:01 +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 " ,
2022-08-28 18:47:01 +08:00
version - > Major ,
version - > Minor ,
version - > Bugfix ,
version - > Build ) ;
2015-03-13 14:48:53 +08:00
}
}
2022-08-28 18:47:01 +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 : : Region , Subtypes : : MeRegion , name , UString ( ) , info , UByteArray ( ) , me , UByteArray ( ) , Fixed , parent ) ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name ( " PDR region " ) ;
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) pdr . size ( ) , ( UINT32 ) 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 ) ;
2022-08-28 18:47:01 +08:00
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 ;
2022-08-28 18:47:01 +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
USTATUS FfsParser : : parseDevExp1Region ( const UByteArray & devExp1 , const UINT32 localOffset , const UModelIndex & parent , UModelIndex & index )
{
// Check sanity
if ( devExp1 . isEmpty ( ) )
return U_EMPTY_REGION ;
2022-08-28 18:47:01 +08:00
2019-09-05 08:07:18 +08:00
// Get info
UString name ( " DevExp1 region " ) ;
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) devExp1 . size ( ) , ( UINT32 ) devExp1 . size ( ) ) ;
2019-09-05 08:07:18 +08:00
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 " ) ;
}
2022-08-28 18:47:01 +08:00
2019-09-05 08:07:18 +08:00
// Add tree item
index = model - > addItem ( localOffset , Types : : Region , Subtypes : : DevExp1Region , name , UString ( ) , info , UByteArray ( ) , devExp1 , UByteArray ( ) , Fixed , parent ) ;
2022-08-28 18:47:01 +08:00
2019-09-05 08:07:18 +08:00
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 ;
2022-08-28 18:47:01 +08:00
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 " ) ;
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) region . size ( ) , ( UINT32 ) 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 ) ;
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name ( " BIOS region " ) ;
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) bios . size ( ) , ( UINT32 ) 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 ) ;
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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 ) ;
2021-04-04 17:09:23 +08:00
UINT32 headerSize = ( UINT32 ) model - > header ( index ) . size ( ) ;
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
USTATUS result ;
2018-10-08 17:58:12 +08:00
UString name ;
UString info ;
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
result = findNextRawAreaItem ( index , 0 , prevItemType , prevItemOffset , prevItemSize , prevItemAltSize ) ;
if ( result ) {
// No need to parse further
return U_SUCCESS ;
}
2022-08-28 18:47:01 +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 ) {
2022-08-29 14:23:38 +08:00
protectedRegionsBase = ( UINT64 ) model - > base ( index ) + prevItemOffset ;
2019-01-07 21:05:57 +08:00
}
2022-08-28 18:47:01 +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 " ) ;
2022-08-28 18:47:01 +08:00
info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) padding . size ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
name = UString ( " Padding " ) ;
2022-08-28 18:47:01 +08:00
info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) padding . size ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
name = UString ( " Padding " ) ;
2022-08-28 18:47:01 +08:00
info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) padding . size ( ) , ( UINT32 ) 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 ) ;
2022-10-09 13:18:28 +08:00
msg ( usprintf ( " %s: one of objects inside overlaps the end of data " , __FUNCTION__ ) , paddingIndex ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Update variables
2018-10-08 17:58:12 +08:00
prevItemOffset = itemOffset ;
2021-04-04 17:09:23 +08:00
prevItemSize = ( UINT32 ) padding . size ( ) ;
2015-03-13 14:48:53 +08:00
break ;
}
2022-08-28 18:47:01 +08:00
2022-08-28 14:00:05 +08:00
// Parse current volume 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__ ,
2022-08-28 18:47:01 +08:00
itemSize , itemAltSize ) ,
volumeIndex ) ;
2018-10-08 17:58:12 +08:00
}
}
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 ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
name = UString ( " BPDT region " ) ;
2022-08-28 18:47:01 +08:00
info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) bpdtStore . size ( ) , ( UINT32 ) bpdtStore . size ( ) ) ;
2019-08-20 02:36:02 +08:00
// Add tree item
UModelIndex bpdtIndex = model - > addItem ( headerSize + itemOffset , Types : : BpdtStore , 0 , name , UString ( ) , info , UByteArray ( ) , bpdtStore , UByteArray ( ) , Fixed , index ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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
}
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
name = UString ( " Padding " ) ;
2022-08-28 18:47:01 +08:00
info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) padding . size ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +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 + + ) {
2021-04-04 17:09:23 +08:00
UModelIndex current = index . model ( ) - > index ( i , 0 , index ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
switch ( model - > type ( current ) ) {
2022-08-28 18:47:01 +08:00
case Types : : Volume :
parseVolumeBody ( current ) ;
break ;
case Types : : Microcode :
// Parsing already done
break ;
case Types : : BpdtStore :
// Parsing already done
break ;
case Types : : BpdtPartition :
// Parsing already done
break ;
case Types : : Padding :
// No parsing required
break ;
default :
return U_UNKNOWN_ITEM_TYPE ;
2015-03-13 14:48:53 +08:00
}
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2015-12-12 17:59:38 +08:00
// Check that there is space for the volume header
2021-10-07 23:51:39 +08:00
if ( ( UINT32 ) volume . size ( ) < sizeof ( EFI_FIRMWARE_VOLUME_HEADER ) ) {
2022-08-28 18:47:01 +08:00
msg ( usprintf ( " %s: input volume size %Xh (%u) is smaller than volume header size 40h (64) " , __FUNCTION__ , ( UINT32 ) volume . size ( ) , ( UINT32 ) volume . size ( ) ) ) ;
2016-06-26 11:54:21 +08:00
return U_INVALID_VOLUME ;
2015-12-12 17:59:38 +08:00
}
2022-08-28 18:47:01 +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 ( ) ) ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Extended header end can be unaligned
headerSize = ALIGN8 ( headerSize ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// 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 ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// 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 ;
}
2022-08-28 18:47:01 +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
2022-08-25 04:17:51 +08:00
if ( ! isUnknown
& & ! model - > compressed ( parent ) // Alignment checks don't really make sense for compressed volumes because they have to be extracted into memory, and by that point it's unlikely that the module doing such extraction will misalign them
& & ( ( model - > base ( parent ) + localOffset - imageBase ) % alignment ) ! = 0 ) // Explicit "is not zero" here for better code readability
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
}
2022-08-28 18:47:01 +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 ' ;
2022-08-28 18:47:01 +08:00
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 ;
2021-04-04 17:09:23 +08:00
UINT32 volumeSize = ( UINT32 ) 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
}
}
2022-08-28 18:47:01 +08:00
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 ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// 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 "
2022-08-28 18:47:01 +08:00
" %02X %02X %02X %02X %02X %02X %02X %02X \n Signature: _FVH \n FileSystem GUID: " ,
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 ] )
+ guidToUString ( volumeHeader - > FileSystemGuid , false ) \
+ 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 " ,
volumeSize , volumeSize ,
headerSize , headerSize ,
volumeSize - headerSize , volumeSize - headerSize ,
volumeHeader - > Revision ,
volumeHeader - > Attributes ,
( emptyByte ? 1 : 0 ) ,
volumeHeader - > Checksum ) +
( 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: " ,
2022-08-28 18:47:01 +08:00
extendedHeader - > ExtHeaderSize , extendedHeader - > ExtHeaderSize ) + guidToUString ( extendedHeader - > FvName , false ) ;
2017-02-14 14:39:16 +08:00
name = guidToUString ( extendedHeader - > FvName ) ; // Replace FFS GUID with volume GUID
2015-03-13 14:48:53 +08:00
}
2022-08-28 18:47:01 +08:00
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 " ) ;
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:47:01 +08:00
2016-12-04 06:36:01 +08:00
// Set parsing data for created volume
2022-08-28 14:00:05 +08:00
VOLUME_PARSING_DATA pdata = { } ;
2016-10-28 00:31:15 +08:00
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 ) ) ) ;
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
2019-09-05 08:07:18 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2019-09-05 08:07:18 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
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 ) ;
2021-04-04 17:09:23 +08:00
UINT32 dataSize = ( UINT32 ) data . size ( ) ;
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
if ( dataSize < sizeof ( UINT32 ) )
return U_STORES_NOT_FOUND ;
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2019-11-28 00:46:16 +08:00
// Check size candidate
if ( ucodeHeader - > TotalSize = = 0 )
continue ;
2022-08-28 18:47:01 +08:00
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 ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
2021-10-07 23:51:39 +08:00
// Calculate alternative volume size using its BlockMap
2018-10-08 17:58:12 +08:00
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 ( ) ) {
2022-08-28 18:47:01 +08:00
continue ;
2018-10-08 17:58:12 +08:00
}
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
nextItemAlternativeSize + = entry - > NumBlocks * entry - > Length ;
entry + = 1 ;
}
2022-08-28 18:47:01 +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 ;
}
2022-09-10 15:56:14 +08:00
else if ( readUnaligned ( currentPos ) = = BPDT_GREEN_SIGNATURE
| | readUnaligned ( currentPos ) = = BPDT_YELLOW_SIGNATURE ) {
2019-08-20 02:36:02 +08:00
// Check data size
if ( restSize < sizeof ( BPDT_HEADER ) )
continue ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
const BPDT_HEADER * bpdtHeader = ( const BPDT_HEADER * ) currentPos ;
2022-10-09 13:18:28 +08:00
// Check NumEntries to be sane
if ( bpdtHeader - > NumEntries > 0x100 )
continue ;
// Check HeaderVersion to be 1
if ( bpdtHeader - > HeaderVersion ! = BPDT_HEADER_VERSION_1 ) // Check only for IFWI 2.0 headers in raw areas
continue ;
// Check RedundancyFlag to be 0 or 1
if ( bpdtHeader - > RedundancyFlag ! = 0 & & bpdtHeader - > RedundancyFlag ! = 1 ) // Check only for IFWI 2.0 headers in raw areas
2019-08-20 02:36:02 +08:00
continue ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
UINT32 ptBodySize = bpdtHeader - > NumEntries * sizeof ( BPDT_ENTRY ) ;
UINT32 ptSize = sizeof ( BPDT_HEADER ) + ptBodySize ;
// Check data size again
if ( restSize < ptSize )
continue ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
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 ) {
2022-08-28 18:47:01 +08:00
sizeCandidate = ptEntry - > Offset + ptEntry - > Size ;
2019-08-20 02:36:02 +08:00
}
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Check size candidate
if ( sizeCandidate = = 0 )
continue ;
2022-08-28 18:47:01 +08:00
// All checks passed, BPDT found
2019-08-20 02:36:02 +08:00
nextItemType = Types : : BpdtStore ;
nextItemSize = sizeCandidate ;
nextItemAlternativeSize = sizeCandidate ;
nextItemOffset = offset ;
break ;
}
2018-10-08 17:58:12 +08:00
}
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
// No more stores found
2019-11-28 00:46:16 +08:00
if ( offset > = dataSize - sizeof ( UINT32 ) ) {
2018-10-08 17:58:12 +08:00
return U_STORES_NOT_FOUND ;
2019-11-28 00:46:16 +08:00
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2015-09-19 16:08:26 +08:00
// Get info
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) data . size ( ) , ( UINT32 ) 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 ) ;
2022-08-28 18:47:01 +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
2020-11-03 16:32:54 +08:00
if ( ! index . isValid ( ) ) {
2016-06-26 11:54:21 +08:00
return U_INVALID_PARAMETER ;
2020-11-03 16:32:54 +08:00
}
2022-08-28 18:47:01 +08:00
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 ) ;
2021-04-04 17:09:23 +08:00
UINT32 volumeHeaderSize = ( UINT32 ) model - > header ( index ) . size ( ) ;
2022-08-28 18:47:01 +08:00
2016-03-28 21:03:32 +08:00
// Parse VSS NVRAM volumes with a dedicated function
2020-11-03 16:32:54 +08:00
if ( model - > subtype ( index ) = = Subtypes : : NvramVolume ) {
2017-12-11 09:56:00 +08:00
return nvramParser - > parseNvramVolumeBody ( index ) ;
2020-11-03 16:32:54 +08:00
}
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
// Parse Microcode volume with a dedicated function
2020-11-03 16:32:54 +08:00
if ( model - > subtype ( index ) = = Subtypes : : MicrocodeVolume ) {
2018-10-08 17:58:12 +08:00
return parseMicrocodeVolumeBody ( index ) ;
2020-11-03 16:32:54 +08:00
}
2022-08-28 18:47:01 +08:00
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 ;
2022-10-07 20:40:20 +08:00
UINT8 revision = 2 ;
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 ;
2022-10-07 20:40:20 +08:00
revision = pdata - > revision ;
2016-10-28 00:31:15 +08:00
}
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Check for unknown FFS version
2020-11-03 16:32:54 +08:00
if ( ffsVersion ! = 2 & & ffsVersion ! = 3 ) {
msg ( usprintf ( " %s: unknown FFS version %d " , __FUNCTION__ , ffsVersion ) , index ) ;
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2020-11-03 16:32:54 +08:00
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Search for and parse all files
2021-04-04 17:09:23 +08:00
UINT32 volumeBodySize = ( UINT32 ) volumeBody . size ( ) ;
2015-03-13 14:48:53 +08:00
UINT32 fileOffset = 0 ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
while ( fileOffset < volumeBodySize ) {
2022-10-07 20:40:20 +08:00
UINT32 fileSize = getFileSize ( volumeBody , fileOffset , ffsVersion , revision ) ;
2022-08-28 18:47:01 +08:00
2020-01-25 03:36:39 +08:00
if ( fileSize = = 0 ) {
msg ( usprintf ( " %s: file header parsing failed with invalid size " , __FUNCTION__ ) , index ) ;
2020-11-03 16:32:54 +08:00
break ; // Exit from parsing loop
2020-01-25 03:36:39 +08:00
}
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ;
2021-04-04 17:09:23 +08:00
UINT32 size = ( UINT32 ) freeSpace . size ( ) ;
2019-01-04 03:53:31 +08:00
const UINT8 * current = ( UINT8 * ) freeSpace . constData ( ) ;
for ( i = 0 ; i < size ; i + + ) {
2020-11-03 16:32:54 +08:00
if ( * current + + ! = emptyByte ) {
break ; // Exit from parsing loop
}
2015-03-13 14:48:53 +08:00
}
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
2019-01-04 03:53:31 +08:00
// Add all bytes before as free space
if ( i > 0 ) {
UByteArray free = freeSpace . left ( i ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) free . size ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +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
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) freeSpace . size ( ) , ( UINT32 ) freeSpace . size ( ) ) ;
2019-01-04 03:53:31 +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 ( ) , freeSpace , UByteArray ( ) , Movable , index ) ;
2015-03-13 14:48:53 +08:00
}
2022-08-28 18:47:01 +08:00
2019-01-04 03:53:31 +08:00
break ; // Exit from parsing loop
2015-03-13 14:48:53 +08:00
}
2022-08-28 18:47:01 +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
2022-09-10 15:56:14 +08:00
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
2019-01-04 03:53:31 +08:00
// Parse non-UEFI data
parseVolumeNonUefiData ( volumeBody . mid ( fileOffset ) , volumeHeaderSize + fileOffset , index ) ;
2022-08-28 18:47:01 +08:00
2019-01-04 03:53:31 +08:00
break ; // Exit from parsing loop
2015-03-13 14:48:53 +08:00
}
2022-08-28 18:47:01 +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 ) ;
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Move to next file
fileOffset + = fileSize ;
2022-08-28 14:00:05 +08:00
// TODO: check that alignment bytes are all of erase polarity bit, warn if not so
2015-03-13 14:48:53 +08:00
fileOffset = ALIGN8 ( fileOffset ) ;
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Check for duplicate GUIDs
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2021-04-04 17:09:23 +08:00
UModelIndex current = index . model ( ) - > index ( i , 0 , index ) ;
2022-08-28 18:47:01 +08:00
2022-09-10 15:56:14 +08:00
// Skip non-file entries and padding files
if ( model - > type ( current ) ! = Types : : File
| | model - > subtype ( current ) = = EFI_FV_FILETYPE_PAD ) {
2015-03-13 14:48:53 +08:00
continue ;
2020-11-03 16:32:54 +08:00
}
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Get current file GUID
UByteArray currentGuid ( model - > header ( current ) . constData ( ) , sizeof ( EFI_GUID ) ) ;
2022-08-28 18:47:01 +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 + + ) {
2021-04-04 17:09:23 +08:00
UModelIndex another = index . model ( ) - > index ( j , 0 , index ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Skip non-file entries
2020-11-03 16:32:54 +08:00
if ( model - > type ( another ) ! = Types : : File ) {
2015-03-13 14:48:53 +08:00
continue ;
2020-11-03 16:32:54 +08:00
}
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Get another file GUID
UByteArray anotherGuid ( model - > header ( another ) . constData ( ) , sizeof ( EFI_GUID ) ) ;
2022-08-28 18:47:01 +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
}
}
}
2022-08-28 18:47:01 +08:00
2020-11-03 16:32:54 +08:00
// Parse bodies
2015-03-13 14:48:53 +08:00
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2021-04-04 17:09:23 +08:00
UModelIndex current = index . model ( ) - > index ( i , 0 , index ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
switch ( model - > type ( current ) ) {
2022-08-28 18:47:01 +08:00
case Types : : File :
parseFileBody ( current ) ;
break ;
case Types : : Padding :
case Types : : FreeSpace :
// No parsing required
break ;
default :
return U_UNKNOWN_ITEM_TYPE ;
2015-03-13 14:48:53 +08:00
}
}
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2022-10-07 20:40:20 +08:00
UINT32 FfsParser : : getFileSize ( const UByteArray & volume , const UINT32 fileOffset , const UINT8 ffsVersion , const UINT8 revision )
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 ;
}
2022-08-28 18:47:01 +08:00
2018-04-30 13:33:19 +08:00
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) ( volume . constData ( ) + fileOffset ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
if ( ffsVersion = = 2 ) {
2022-10-07 20:40:20 +08:00
UINT32 size = uint24ToUint32 ( fileHeader - > Size ) ;
// Special case of Lenovo large file insize FFSv2 Rev2 volume
if ( revision = = 2 & & ( fileHeader - > Attributes & FFS_ATTRIB_LARGE_FILE ) ) {
if ( ( UINT32 ) volume . size ( ) < fileOffset + sizeof ( EFI_FFS_FILE_HEADER2_LENOVO ) ) {
return 0 ;
}
const EFI_FFS_FILE_HEADER2_LENOVO * fileHeader2Lenovo = ( const EFI_FFS_FILE_HEADER2_LENOVO * ) ( volume . constData ( ) + fileOffset ) ;
return ( UINT32 ) fileHeader2Lenovo - > ExtendedSize ;
}
return size ;
2015-03-13 14:48:53 +08:00
}
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 ;
}
2022-08-28 18:47:01 +08:00
2018-04-30 13:33:19 +08:00
const EFI_FFS_FILE_HEADER2 * fileHeader2 = ( const EFI_FFS_FILE_HEADER2 * ) ( volume . constData ( ) + fileOffset ) ;
2022-10-07 20:40:20 +08:00
return ( UINT32 ) fileHeader2 - > ExtendedSize ;
2018-04-30 13:33:19 +08:00
}
2022-08-28 18:47:01 +08:00
2018-04-30 13:33:19 +08:00
return uint24ToUint32 ( fileHeader - > Size ) ;
2015-03-13 14:48:53 +08:00
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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 ( ) ;
2022-10-07 20:40:20 +08:00
if ( tempFileHeader - > Attributes & FFS_ATTRIB_LARGE_FILE ) {
if ( ffsVersion = = 2 & & volumeRevision = = 2 ) {
if ( ( UINT32 ) file . size ( ) < sizeof ( EFI_FFS_FILE_HEADER2_LENOVO ) )
return U_INVALID_FILE ;
header = file . left ( sizeof ( EFI_FFS_FILE_HEADER2_LENOVO ) ) ;
}
if ( ffsVersion = = 3 ) {
if ( ( UINT32 ) file . size ( ) < sizeof ( EFI_FFS_FILE_HEADER2 ) )
return U_INVALID_FILE ;
header = file . left ( sizeof ( EFI_FFS_FILE_HEADER2 ) ) ;
}
2015-03-13 14:48:53 +08:00
}
2017-12-11 09:56:00 +08:00
const EFI_FFS_FILE_HEADER * fileHeader = ( const EFI_FFS_FILE_HEADER * ) header . constData ( ) ;
2022-08-28 18:47:01 +08:00
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 ] ;
2020-02-09 03:05:33 +08:00
}
2022-08-28 18:47:01 +08:00
2017-12-11 09:56:00 +08:00
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
}
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
// Check file alignment against 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
}
2022-08-28 18:47:01 +08:00
2017-12-11 09:56:00 +08:00
// Get file body
UByteArray body = file . mid ( header . size ( ) ) ;
2022-08-28 18:47:01 +08:00
2017-12-11 09:56:00 +08:00
// 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 ;
2022-08-28 18:47:01 +08:00
2017-12-11 09:56:00 +08:00
// Get tail and remove it from file body
tail = body . right ( sizeof ( UINT16 ) ) ;
body = body . left ( body . size ( ) - sizeof ( UINT16 ) ) ;
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Check header checksum
2021-04-04 17:09:23 +08:00
UINT8 calculatedHeader = 0x100 - ( calculateSum8 ( ( const UINT8 * ) header . constData ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +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 ) {
2021-04-04 17:09:23 +08:00
calculatedData = calculateChecksum8 ( ( const UINT8 * ) body . constData ( ) , ( UINT32 ) 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 ;
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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 ;
} ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// 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 {
2022-09-10 15:56:14 +08:00
name = UString ( " Padding file " ) ;
2018-04-30 13:33:19 +08:00
}
2022-08-28 18:47:01 +08:00
2017-02-14 14:39:16 +08:00
info = UString ( " File GUID: " ) + guidToUString ( fileHeader - > Name , false ) +
2022-08-28 18:47:01 +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 " ,
fileHeader - > Type ,
fileHeader - > Attributes ,
( UINT32 ) ( header . size ( ) + body . size ( ) + tail . size ( ) ) , ( UINT32 ) ( header . size ( ) + body . size ( ) + tail . size ( ) ) ,
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
( UINT32 ) body . size ( ) , ( UINT32 ) body . size ( ) ,
( UINT32 ) tail . size ( ) , ( UINT32 ) tail . size ( ) ,
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 " ) ) ;
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
2020-02-09 03:05:33 +08:00
// Because the last byte of the last VFT is mapped to 0xFFFFFFFF physical memory address
2015-06-20 02:26:45 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Construct fixed state
ItemFixedState fixed = ( ItemFixedState ) ( ( fileHeader - > Attributes & FFS_ATTRIB_FIXED ) ! = 0 ) ;
2022-08-28 18:47:01 +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 : : File , fileHeader - > Type , name , text , info , header , body , tail , fixed , parent ) ;
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Set parsing data for created file
2022-08-28 14:00:05 +08:00
FILE_PARSING_DATA pdata = { } ;
2016-10-28 00:31:15 +08:00
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 ) ) ) ;
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
// Override first DXE core index, if needed
2022-08-29 14:23:38 +08:00
if ( isDxeCore & & ! dxeCore . isValid ( ) ) {
dxeCore = index ;
2017-10-12 13:59:23 +08:00
}
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2018-04-30 13:33:19 +08:00
return size ;
2015-03-13 14:48:53 +08:00
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
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 ;
2022-08-28 18:47:01 +08:00
2022-09-10 15:56:14 +08:00
// Parse padding file body
2015-03-13 14:48:53 +08:00
if ( model - > subtype ( index ) = = EFI_FV_FILETYPE_PAD )
return parsePadFileBody ( index ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// 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 ) ) ;
2022-08-28 18:47:01 +08:00
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 ) {
2022-09-13 16:21:25 +08:00
model - > setText ( index , UString ( " NVAR BB defaults " ) ) ;
2019-04-12 00:30:30 +08:00
return nvramParser - > parseNvarStore ( index ) ;
}
2017-10-12 13:59:23 +08:00
// Parse vendor hash file
2022-08-29 14:23:38 +08:00
else if ( fileGuid = = PROTECTED_RANGE_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
}
2022-09-13 16:21:25 +08:00
// Parse AMI ROM hole
else if ( fileGuid = = AMI_ROM_HOLE_FILE_GUID_0
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_1
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_2
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_3
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_4
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_5
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_6
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_7
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_8
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_9
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_10
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_11
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_12
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_13
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_14
| | fileGuid = = AMI_ROM_HOLE_FILE_GUID_15 ) {
model - > setText ( index , UString ( " AMI ROM hole " ) ) ;
// Mark ROM hole file as Fixed in the image
model - > setFixed ( index , Fixed ) ;
// No need to parse further
return U_SUCCESS ;
}
2022-08-28 18:47:01 +08:00
2016-04-17 07:25:44 +08:00
return parseRawArea ( index ) ;
2016-03-21 06:59:03 +08:00
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2022-09-10 15:56:14 +08:00
// Check if the while padding file is empty
2016-10-28 00:31:15 +08:00
if ( body . size ( ) = = body . count ( emptyByte ) )
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2022-08-28 18:47:01 +08:00
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 ;
2021-04-04 17:09:23 +08:00
UINT32 size = ( UINT32 ) body . size ( ) ;
2015-03-13 14:48:53 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Add all bytes before as free space...
2021-04-04 17:09:23 +08:00
UINT32 headerSize = ( UINT32 ) 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 ;
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
UByteArray free = body . left ( nonEmptyByteOffset ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) free . size ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:47:01 +08:00
2022-09-10 15:56:14 +08:00
// Check for that data to be recovery startup AP data for x86
// https://github.com/tianocore/edk2/blob/stable/202011/BaseTools/Source/C/GenFv/GenFvInternalLib.c#L106
if ( padding . left ( RECOVERY_STARTUP_AP_DATA_X86_SIZE ) = = RECOVERY_STARTUP_AP_DATA_X86_128K ) {
// Get info
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) padding . size ( ) , ( UINT32 ) padding . size ( ) ) ;
// Add tree item
( void ) model - > addItem ( headerSize + nonEmptyByteOffset , Types : : StartupApDataEntry , Subtypes : : x86128kStartupApDataEntry , UString ( " Startup AP data " ) , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
// Rename the file
model - > setName ( index , UString ( " Startup AP data padding file " ) ) ;
// Do not parse contents
return U_SUCCESS ;
}
else { // Not a data array
// Get info
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) padding . size ( ) , ( UINT32 ) padding . size ( ) ) ;
// Add tree item
UModelIndex dataIndex = model - > addItem ( headerSize + nonEmptyByteOffset , Types : : Padding , Subtypes : : DataPadding , UString ( " Non-UEFI data " ) , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , index ) ;
// Show message
msg ( usprintf ( " %s: non-UEFI data found in padding file " , __FUNCTION__ ) , dataIndex ) ;
// Rename the file
model - > setName ( index , UString ( " Non-empty padding file " ) ) ;
// Do not parse contents
return U_SUCCESS ;
}
2022-08-28 18:47:01 +08:00
2022-09-10 15:56:14 +08:00
return U_SUCCESS ;
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 ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Search for and parse all sections
2021-04-04 17:09:23 +08:00
UINT32 bodySize = ( UINT32 ) sections . size ( ) ;
UINT32 headerSize = ( UINT32 ) model - > header ( index ) . size ( ) ;
2015-03-13 14:48:53 +08:00
UINT32 sectionOffset = 0 ;
2016-06-26 11:54:21 +08:00
USTATUS result = U_SUCCESS ;
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
// Iterate over sections
UINT32 sectionSize = 0 ;
2015-03-13 14:48:53 +08:00
while ( sectionOffset < bodySize ) {
// Get section size
2022-08-25 04:17:51 +08:00
sectionSize = getSectionSize ( sections , sectionOffset , ffsVersion ) ;
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
// Check section size to be sane
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 ) ;
2022-08-28 18:47:01 +08:00
2016-07-16 13:02:33 +08:00
// Get info
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) padding . size ( ) , ( UINT32 ) 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 ) ;
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
2016-07-16 13:02:33 +08:00
// Exit from parsing loop
2020-02-09 03:05:33 +08:00
break ;
2016-02-02 09:08:08 +08:00
}
2022-08-25 04:17:51 +08:00
// Preliminary parsing
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
}
2022-08-28 18:47:01 +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 )
2022-08-28 14:00:05 +08:00
msg ( usprintf ( " %s: section header parsing failed with error " , __FUNCTION__ ) + 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
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Move to next section
sectionOffset + = sectionSize ;
2022-08-25 04:17:51 +08:00
// TODO: verify that alignment bytes are actually zero as per PI spec
2015-03-13 14:48:53 +08:00
sectionOffset = ALIGN4 ( sectionOffset ) ;
}
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
#if 0 // Do not enable this in production for now, as it needs further investigation.
// The PI spec requires sections to be aligned by 4 byte boundary with bytes that are all exactly zeroes
// Some images interpret "must be aligned by 4" as "every section needs to be padded for sectionSize to be divisible by 4".
// Detecting this case can be done by checking for the very last section to have sectionSize not divisible by 4, while the total bodySize is.
// However, such detection for a single file is unreliable because in 1/4 random cases the last section will be divisible by 4.
// We also know that either PEI core or DXE core is entity that does file and section parsing,
// so every single file in the volume should behave consistently.
// This makes the probability of unsuccessful detection here to be 1/(4^numFilesInVolume),
// which is low enough for real images out there.
// It should also be noted that enabling this section alignment quirk for an image that doesn't require it
// will not make the image unbootable, but will waste some space and possibly require to move some files around
if ( sectionOffset = = bodySize ) {
// We are now at the very end of the file body, and sectionSize is the size of the last section
if ( ( sectionSize % 4 ! = 0 ) // sectionSize of the very last section is not divisible by 4
& & ( bodySize % 4 = = 0 ) ) { // yet bodySize is, meaning that there are indeed some padding bytes added after the last section
msg ( usprintf ( " %s: section alignment quirk found " , __FUNCTION__ ) , index ) ;
}
}
# endif
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 + + ) {
2021-04-04 17:09:23 +08:00
UModelIndex current = index . model ( ) - > index ( i , 0 , index ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
switch ( model - > type ( current ) ) {
2022-08-28 18:47:01 +08:00
case Types : : Section :
parseSectionBody ( current ) ;
break ;
case Types : : Padding :
// No parsing required
break ;
default :
return U_UNKNOWN_ITEM_TYPE ;
2015-03-13 14:48:53 +08:00
}
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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 ) {
2022-08-28 18:47:01 +08:00
// Special
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 ) ;
case PHOENIX_SECTION_POSTCODE :
case INSYDE_SECTION_POSTCODE : return parsePostcodeSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
// Common
case EFI_SECTION_DISPOSABLE :
case EFI_SECTION_DXE_DEPEX :
case EFI_SECTION_PEI_DEPEX :
case EFI_SECTION_MM_DEPEX :
case EFI_SECTION_PE32 :
case EFI_SECTION_PIC :
case EFI_SECTION_TE :
case EFI_SECTION_COMPATIBILITY16 :
case EFI_SECTION_USER_INTERFACE :
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE :
case EFI_SECTION_RAW : return parseCommonSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
// Unknown
default :
USTATUS result = parseCommonSectionHeader ( section , localOffset , parent , index , insertIntoTree ) ;
msg ( usprintf ( " %s: section with unknown type %02Xh " , __FUNCTION__ , sectionHeader - > Type ) , index ) ;
return result ;
2015-03-13 14:48:53 +08:00
}
}
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
}
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Obtain header fields
2022-08-25 04:17:51 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( section . constData ( ) ) ;
UINT32 headerSize = sizeof ( EFI_COMMON_SECTION_HEADER ) ;
2022-08-28 18:47:01 +08:00
if ( ffsVersion = = 3 & & uint24ToUint32 ( sectionHeader - > Size ) = = EFI_SECTION2_IS_USED )
headerSize = sizeof ( EFI_COMMON_SECTION_HEADER2 ) ;
2022-08-25 04:17:51 +08:00
UINT8 type = sectionHeader - > Type ;
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
}
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( type ) + UString ( " section " ) ;
2022-08-28 18:01:43 +08:00
UString info = usprintf ( " Type: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) " ,
2022-08-28 18:47:01 +08:00
type ,
( UINT32 ) section . size ( ) , ( UINT32 ) section . size ( ) ,
headerSize , headerSize ,
( UINT32 ) body . size ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
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 ( ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
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 ;
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2022-08-28 18:47:01 +08:00
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 " ) ;
2022-08-28 18:01:43 +08:00
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) " ,
2022-08-28 18:47:01 +08:00
sectionHeader - > Type ,
( UINT32 ) section . size ( ) , ( UINT32 ) section . size ( ) ,
headerSize , headerSize ,
( UINT32 ) body . size ( ) , ( UINT32 ) 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 ) ;
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Set section parsing data
2022-08-28 14:00:05 +08:00
COMPRESSED_SECTION_PARSING_DATA pdata = { } ;
2016-10-28 00:31:15 +08:00
pdata . compressionType = compressionType ;
pdata . uncompressedSize = uncompressedLength ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2016-02-09 19:00:14 +08:00
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
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 ( ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
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 ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
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 ;
2022-08-28 18:47:01 +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
2021-04-04 17:09:23 +08:00
UINT32 calculated = ( UINT32 ) crc32 ( 0 , ( const UINT8 * ) section . constData ( ) + dataOffset , ( uInt ) ( 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
}
2022-08-24 11:01:00 +08:00
else if ( baGuid = = EFI_GUIDED_SECTION_LZMA | | baGuid = = EFI_GUIDED_SECTION_LZMA_HP | | 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 ;
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
// Get certificate type and length
if ( ( UINT32 ) section . size ( ) < headerSize + sizeof ( EFI_CERT_BLOCK_RSA2048_SHA256 ) )
return U_INVALID_SECTION ;
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
2015-12-12 17:59:38 +08:00
// 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 ;
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2015-12-12 17:59:38 +08:00
// Adjust dataOffset
dataOffset + = certLength ;
2022-08-28 18:47:01 +08:00
2015-12-12 17:59:38 +08:00
// Check section size once again
if ( ( UINT32 ) section . size ( ) < dataOffset )
2016-06-26 11:54:21 +08:00
return U_INVALID_SECTION ;
2022-08-28 18:47:01 +08:00
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 " ) ;
2022-08-28 18:47:01 +08:00
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 ) ) ;
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( dataOffset ) ;
UByteArray body = section . mid ( dataOffset ) ;
2022-08-28 18:47:01 +08:00
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 ) +
2022-08-28 18:47:01 +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 ,
( UINT32 ) section . size ( ) , ( UINT32 ) section . size ( ) ,
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
( UINT32 ) body . size ( ) , ( UINT32 ) body . size ( ) ,
dataOffset ,
attributes ) ;
2015-12-12 17:59:38 +08:00
// Append additional info
2016-06-26 16:05:45 +08:00
info + = additionalInfo ;
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Set parsing data
2022-08-28 14:00:05 +08:00
GUIDED_SECTION_PARSING_DATA pdata = { } ;
2016-10-28 00:31:15 +08:00
pdata . guid = guid ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
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 ( ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( type ) + ( " section " ) ;
2022-08-28 18:01:43 +08:00
UString info = usprintf ( " Type: %02Xh \n Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Subtype GUID: " ,
2022-08-28 18:47:01 +08:00
type ,
( UINT32 ) section . size ( ) , ( UINT32 ) section . size ( ) ,
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
( UINT32 ) body . size ( ) , ( UINT32 ) body . size ( ) )
+ 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 ) ;
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Set parsing data
2022-08-28 14:00:05 +08:00
FREEFORM_GUIDED_SECTION_PARSING_DATA pdata = { } ;
2016-10-28 00:31:15 +08:00
pdata . guid = guid ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
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 ( ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
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 ;
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( type ) + ( " section " ) ;
2022-08-28 18:01:43 +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 " ,
2022-08-28 18:47:01 +08:00
type ,
( UINT32 ) section . size ( ) , ( UINT32 ) section . size ( ) ,
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
( UINT32 ) body . size ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
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 ( ) ) ;
2022-08-25 04:17:51 +08:00
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 ;
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
UByteArray header = section . left ( headerSize ) ;
UByteArray body = section . mid ( headerSize ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Get info
2016-06-26 11:54:21 +08:00
UString name = sectionTypeToUString ( type ) + ( " section " ) ;
2022-08-28 18:01:43 +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 " ,
2022-08-28 18:47:01 +08:00
type ,
( UINT32 ) section . size ( ) , ( UINT32 ) section . size ( ) ,
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
( UINT32 ) body . size ( ) , ( UINT32 ) 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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2016-03-21 06:59:03 +08:00
const EFI_COMMON_SECTION_HEADER * sectionHeader = ( const EFI_COMMON_SECTION_HEADER * ) ( header . constData ( ) ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
switch ( sectionHeader - > Type ) {
2022-08-28 18:47:01 +08:00
// Encapsulation
case EFI_SECTION_COMPRESSION : return parseCompressedSectionBody ( index ) ;
case EFI_SECTION_GUID_DEFINED : return parseGuidedSectionBody ( index ) ;
case EFI_SECTION_DISPOSABLE : return parseSections ( model - > body ( index ) , index , true ) ;
// Leaf
case EFI_SECTION_FREEFORM_SUBTYPE_GUID : return parseRawArea ( index ) ;
case EFI_SECTION_VERSION : return parseVersionSectionBody ( index ) ;
case EFI_SECTION_DXE_DEPEX :
case EFI_SECTION_PEI_DEPEX :
case EFI_SECTION_MM_DEPEX : return parseDepexSectionBody ( index ) ;
case EFI_SECTION_TE : return parseTeImageSectionBody ( index ) ;
case EFI_SECTION_PE32 :
case EFI_SECTION_PIC : return parsePeImageSectionBody ( index ) ;
case EFI_SECTION_USER_INTERFACE : return parseUiSectionBody ( index ) ;
case EFI_SECTION_FIRMWARE_VOLUME_IMAGE : return parseRawArea ( index ) ;
case EFI_SECTION_RAW : return parseRawSectionBody ( index ) ;
// No parsing needed
case EFI_SECTION_COMPATIBILITY16 :
case PHOENIX_SECTION_POSTCODE :
case INSYDE_SECTION_POSTCODE :
default :
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 ;
2022-08-28 18:47:01 +08:00
2016-10-28 00:31:15 +08:00
// Obtain required information from parsing data
UINT8 compressionType = EFI_NOT_COMPRESSED ;
2021-04-04 17:09:23 +08:00
UINT32 uncompressedSize = ( UINT32 ) model - > body ( index ) . size ( ) ;
2016-10-28 00:31:15 +08:00
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
}
2022-08-28 18:47:01 +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 ) {
2022-08-28 14:00:05 +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
}
2022-08-28 18:47:01 +08:00
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 ( ) ) {
2022-08-28 18:01:43 +08:00
msg ( usprintf ( " %s: decompressed size stored in header %Xh (%u) differs from actual %Xh (%u) " ,
2022-08-28 18:47:01 +08:00
__FUNCTION__ ,
uncompressedSize , uncompressedSize ,
( UINT32 ) decompressed . size ( ) , ( UINT32 ) decompressed . size ( ) ) ,
2016-10-28 00:31:15 +08:00
index ) ;
2022-08-28 18:47:01 +08:00
model - > addInfo ( index , usprintf ( " \n Actual decompressed size: %Xh (%u) " , ( UINT32 ) decompressed . size ( ) , ( UINT32 ) decompressed . size ( ) ) ) ;
2015-03-13 14:48:53 +08:00
}
2022-08-28 18:47:01 +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 {
2022-08-28 14:00:05 +08:00
msg ( usprintf ( " %s: can't guess the correct decompression algorithm, both preparse steps are failed " , __FUNCTION__ ) , index ) ;
2016-02-02 09:08:08 +08:00
}
}
2022-08-28 18:47:01 +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-11-28 00:46:16 +08:00
if ( algorithm = = COMPRESSION_ALGORITHM_LZMA | | algorithm = = COMPRESSION_ALGORITHM_LZMA_INTEL_LEGACY ) {
2019-01-04 03:53:31 +08:00
model - > addInfo ( index , usprintf ( " \n LZMA dictionary size: %Xh " , dictionarySize ) ) ;
}
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
// Set compression data
if ( algorithm ! = COMPRESSION_ALGORITHM_NONE ) {
model - > setUncompressedData ( index , decompressed ) ;
model - > setCompressed ( index , true ) ;
}
// Set parsing data
2022-08-28 14:00:05 +08:00
COMPRESSED_SECTION_PARSING_DATA pdata = { } ;
2016-10-28 00:31:15 +08:00
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 ) ) ) ;
2022-08-25 04:17:51 +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 ;
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
info + = UString ( " \n Compression algorithm: " ) + compressionTypeToUString ( algorithm ) ;
2022-08-28 18:47:01 +08:00
info + = usprintf ( " \n Decompressed size: %Xh (%u) " , ( UINT32 ) processed . size ( ) , ( UINT32 ) processed . size ( ) ) ;
2015-12-12 17:59:38 +08:00
}
// LZMA compressed section
2022-08-25 04:17:51 +08:00
else if ( baGuid = = EFI_GUIDED_SECTION_LZMA
| | baGuid = = EFI_GUIDED_SECTION_LZMA_HP ) {
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
}
2022-08-28 18:47:01 +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 " ) ;
2022-08-28 18:47:01 +08:00
info + = usprintf ( " \n Decompressed size: %Xh (%u) " , ( UINT32 ) processed . size ( ) , ( UINT32 ) 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
}
2020-03-07 04:54:20 +08:00
// LZMAF86 compressed section
else if ( baGuid = = EFI_GUIDED_SECTION_LZMAF86 ) {
USTATUS result = decompress ( model - > body ( index ) , EFI_CUSTOMIZED_COMPRESSION_LZMAF86 , algorithm , dictionarySize , processed , efiDecompressed ) ;
if ( result ) {
msg ( usprintf ( " %s: decompression failed with error " , __FUNCTION__ ) + errorCodeToUString ( result ) , index ) ;
return U_SUCCESS ;
}
2022-08-28 18:47:01 +08:00
2020-03-07 04:54:20 +08:00
if ( algorithm = = COMPRESSION_ALGORITHM_LZMAF86 ) {
info + = UString ( " \n Compression algorithm: LZMAF86 " ) ;
2022-08-28 18:47:01 +08:00
info + = usprintf ( " \n Decompressed size: %Xh (%u) " , ( UINT32 ) processed . size ( ) , ( UINT32 ) processed . size ( ) ) ;
2020-03-07 04:54:20 +08:00
info + = usprintf ( " \n LZMA dictionary size: %Xh " , dictionarySize ) ;
}
else {
info + = UString ( " \n Compression algorithm: unknown " ) ;
parseCurrentSection = false ;
}
}
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 ;
}
2022-08-28 18:47:01 +08:00
2018-11-11 21:33:13 +08:00
info + = UString ( " \n Compression algorithm: GZip " ) ;
2022-08-28 18:47:01 +08:00
info + = usprintf ( " \n Decompressed size: %Xh (%u) " , ( UINT32 ) processed . size ( ) , ( UINT32 ) processed . size ( ) ) ;
2018-11-11 21:33:13 +08:00
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Add info
model - > addInfo ( index , info ) ;
2022-08-28 18:47:01 +08:00
2019-01-04 03:53:31 +08:00
// Set parsing data
2022-08-28 14:00:05 +08:00
GUIDED_SECTION_PARSING_DATA pdata = { } ;
2019-01-04 03:53:31 +08:00
pdata . dictionarySize = dictionarySize ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-25 04:17:51 +08:00
// Set compression data
if ( algorithm ! = COMPRESSION_ALGORITHM_NONE ) {
model - > setUncompressedData ( index , processed ) ;
model - > setCompressed ( index , true ) ;
}
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Add info
2021-04-04 17:09:23 +08:00
# if QT_VERSION_MAJOR >= 6
model - > addInfo ( index , UString ( " \n Version string: " ) + UString : : fromUtf16 ( ( const char16_t * ) model - > body ( index ) . constData ( ) ) ) ;
# else
2016-06-26 11:54:21 +08:00
model - > addInfo ( index , UString ( " \n Version string: " ) + UString : : fromUtf16 ( ( const CHAR16 * ) model - > body ( index ) . constData ( ) ) ) ;
2021-04-04 17:09:23 +08:00
# endif
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
UByteArray body = model - > body ( index ) ;
UString parsed ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
const EFI_GUID * guid ;
const UINT8 * current = ( const UINT8 * ) body . constData ( ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Special cases of first opcode
switch ( * current ) {
2022-08-28 18:47:01 +08:00
case EFI_DEP_BEFORE :
if ( body . size ( ) ! = 2 * EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ) {
msg ( usprintf ( " %s: DEPEX section too long for a section starting with BEFORE opcode " , __FUNCTION__ ) , index ) ;
return U_SUCCESS ;
}
guid = ( const EFI_GUID * ) ( current + EFI_DEP_OPCODE_SIZE ) ;
parsed + = UString ( " \n BEFORE " ) + guidToUString ( readUnaligned ( guid ) ) ;
current + = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ;
if ( * current ! = EFI_DEP_END ) {
msg ( usprintf ( " %s: DEPEX section ends with non-END opcode " , __FUNCTION__ ) , index ) ;
return U_SUCCESS ;
}
2022-09-10 20:20:49 +08:00
// No further parsing required
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2022-08-28 18:47:01 +08:00
case EFI_DEP_AFTER :
if ( body . size ( ) ! = 2 * EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ) {
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 ) ;
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
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 ) ;
2022-08-28 18:47:01 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
2022-09-10 20:20:49 +08:00
// No further parsing required
2016-06-26 11:54:21 +08:00
return U_SUCCESS ;
2022-08-28 18:47:01 +08:00
case EFI_DEP_SOR :
if ( body . size ( ) < = 2 * EFI_DEP_OPCODE_SIZE ) {
msg ( usprintf ( " %s: DEPEX section too short for a section starting with SOR opcode " , __FUNCTION__ ) , index ) ;
return U_SUCCESS ;
}
parsed + = UString ( " \n SOR " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
2015-03-13 14:48:53 +08:00
break ;
2022-08-28 18:47:01 +08:00
}
// Parse the rest of depex
while ( current - ( const UINT8 * ) body . constData ( ) < body . size ( ) ) {
switch ( * current ) {
case EFI_DEP_BEFORE : {
msg ( usprintf ( " %s: misplaced BEFORE opcode " , __FUNCTION__ ) , index ) ;
return U_SUCCESS ;
}
case EFI_DEP_AFTER : {
msg ( usprintf ( " %s: misplaced AFTER opcode " , __FUNCTION__ ) , index ) ;
return U_SUCCESS ;
}
case EFI_DEP_SOR : {
msg ( usprintf ( " %s: misplaced SOR opcode " , __FUNCTION__ ) , index ) ;
return U_SUCCESS ;
}
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 ( ) ;
msg ( usprintf ( " %s: remains of DEPEX section too short for PUSH opcode " , __FUNCTION__ ) , index ) ;
return U_SUCCESS ;
}
guid = ( const EFI_GUID * ) ( current + EFI_DEP_OPCODE_SIZE ) ;
parsed + = UString ( " \n PUSH " ) + guidToUString ( readUnaligned ( guid ) ) ;
current + = EFI_DEP_OPCODE_SIZE + sizeof ( EFI_GUID ) ;
break ;
case EFI_DEP_AND :
parsed + = UString ( " \n AND " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_OR :
parsed + = UString ( " \n OR " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_NOT :
parsed + = UString ( " \n NOT " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_TRUE :
parsed + = UString ( " \n TRUE " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_FALSE :
parsed + = UString ( " \n FALSE " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
break ;
case EFI_DEP_END :
parsed + = UString ( " \n END " ) ;
current + = EFI_DEP_OPCODE_SIZE ;
// Check that END is the last opcode
if ( current - ( const UINT8 * ) body . constData ( ) < body . size ( ) ) {
parsed . clear ( ) ;
msg ( usprintf ( " %s: DEPEX section ends with non-END opcode " , __FUNCTION__ ) , index ) ;
}
break ;
default :
msg ( usprintf ( " %s: unknown opcode %02Xh " , __FUNCTION__ , * current ) , index ) ;
2022-09-10 20:20:49 +08:00
// No further parsing required
2022-08-28 18:47:01 +08:00
return U_SUCCESS ;
2015-03-13 14:48:53 +08:00
}
}
2022-08-28 18:47:01 +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 Parsed expression: " ) + parsed ) ;
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
2021-04-04 17:09:23 +08:00
# if QT_VERSION_MAJOR >= 6
UString text = UString : : fromUtf16 ( ( const char16_t * ) model - > body ( index ) . constData ( ) ) ;
# else
2016-06-26 11:54:21 +08:00
UString text = UString : : fromUtf16 ( ( const CHAR16 * ) model - > body ( index ) . constData ( ) ) ;
2021-04-04 17:09:23 +08:00
# endif
2022-08-28 18:47:01 +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 Text: " ) + text ) ;
2022-08-28 18:47:01 +08:00
2015-03-13 14:48:53 +08:00
// Rename parent file
model - > setText ( model - > findParentOfType ( index , Types : : File ) , text ) ;
2022-08-28 18:47:01 +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 : : 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 ( ) ;
2021-04-04 17:09:23 +08:00
UINT32 count = ( UINT32 ) ( body . size ( ) / sizeof ( EFI_GUID ) ) ;
2015-04-02 16:04:37 +08:00
if ( count > 0 ) {
for ( UINT32 i = 0 ; i < count ; i + + ) {
const EFI_GUID * guid = ( const EFI_GUID * ) body . constData ( ) + i ;
2022-08-29 14:23:38 +08:00
parsed + = " \n " + guidToUString ( readUnaligned ( guid ) ) ;
2015-04-02 16:04:37 +08:00
}
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +08:00
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 ( ) )
2022-08-29 14:23:38 +08:00
return U_INVALID_RAW_AREA ;
2022-08-28 18:47:01 +08:00
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
}
2022-08-29 14:23:38 +08:00
else if ( parentFileGuid = = PROTECTED_RANGE_VENDOR_HASH_FILE_GUID_AMI ) { // AMI vendor hash file
2017-10-12 13:59:23 +08:00
// 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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +08:00
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
}
2022-08-28 18:47:01 +08:00
2016-06-26 11:54:21 +08:00
info + = usprintf ( " \n DOS signature: %04Xh \n PE signature: %08Xh " ,
2022-08-28 18:47:01 +08:00
dosHeader - > e_magic ,
peHeader - > Signature ) +
UString ( " \n Machine type: " ) + machineTypeToUString ( imageFileHeader - > Machine ) +
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
}
2022-08-28 18:47:01 +08:00
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 " ,
2022-08-28 18:47:01 +08:00
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 " ,
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +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 ) +
2022-08-28 18:47:01 +08:00
UString ( " \n Machine type: " ) + machineTypeToUString ( teHeader - > Machine ) +
usprintf ( " \n Number of sections: %u \n Subsystem: %02Xh \n Stripped size: %Xh (%u) \n "
" Base of code: %Xh \n Address of entry point: %Xh \n Image base: % " PRIX64 " h \n Adjusted image base: % " PRIX64 " h " ,
teHeader - > NumberOfSections ,
teHeader - > Subsystem ,
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
}
2022-08-28 18:47:01 +08:00
2015-06-20 02:26:45 +08:00
// Update parsing data
2022-08-28 14:00:05 +08:00
TE_IMAGE_SECTION_PARSING_DATA pdata = { } ;
2016-10-28 00:31:15 +08:00
pdata . imageBaseType = EFI_IMAGE_TE_BASE_OTHER ; // Will be determined later
2019-11-28 00:46:16 +08:00
pdata . originalImageBase = ( UINT32 ) teHeader - > ImageBase ;
2016-10-28 00:31:15 +08:00
pdata . adjustedImageBase = ( UINT32 ) ( teHeader - > ImageBase + teHeader - > StrippedSize - sizeof ( EFI_IMAGE_TE_HEADER ) ) ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2022-08-28 18:47:01 +08:00
2015-06-20 02:26:45 +08:00
// Add TE info
model - > addInfo ( index , info ) ;
2022-08-28 18:47:01 +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 ;
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +08:00
2015-06-20 02:26:45 +08:00
// Calculate address difference
2021-10-07 23:56:25 +08:00
const UINT32 vtfSize = ( UINT32 ) ( 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 ;
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
// Parse reset vector data
parseResetVectorData ( ) ;
2022-08-28 18:47:01 +08:00
2016-07-15 03:22:51 +08:00
// Find and parse FIT
2022-08-29 14:23:38 +08:00
fitParser - > parseFit ( index ) ;
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
// Check protected ranges
checkProtectedRanges ( index ) ;
2022-08-28 18:47:01 +08:00
2019-01-07 21:05:57 +08:00
// Check TE files to have original or adjusted base
checkTeImageBase ( index ) ;
2022-08-28 18:47:01 +08:00
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 ;
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
// 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 ;
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
const X86_RESET_VECTOR_DATA * resetVectorData = ( const X86_RESET_VECTOR_DATA * ) ( vtf . constData ( ) + vtf . size ( ) - sizeof ( X86_RESET_VECTOR_DATA ) ) ;
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
// 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 "
2022-08-29 14:23:38 +08:00
" AP startup segment: %08Xh \n "
" BootFV base address: %08Xh \n " ,
2022-08-28 18:47:01 +08:00
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 ) ;
2019-07-25 01:30:59 +08:00
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
2022-08-29 14:23:38 +08:00
if ( ! index . isValid ( ) ) {
return U_INVALID_PARAMETER ;
}
2022-08-28 18:47:01 +08:00
2019-01-07 21:05:57 +08:00
// Determine relocation type of uncompressed TE image sections
2020-02-09 03:05:33 +08:00
if ( model - > compressed ( index ) = = false
& & model - > type ( index ) = = Types : : Section
2019-01-07 21:05:57 +08:00
& & 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 ( ) ;
2019-11-28 00:46:16 +08:00
originalImageBase = readUnaligned ( pdata ) . originalImageBase ;
2019-01-07 21:05:57 +08:00
adjustedImageBase = readUnaligned ( pdata ) . adjustedImageBase ;
}
2022-08-28 18:47:01 +08:00
2019-11-28 00:46:16 +08:00
if ( originalImageBase ! = 0 | | adjustedImageBase ! = 0 ) {
// Check data memory address to be equal to either OriginalImageBase or AdjustedImageBase
2019-01-07 21:05:57 +08:00
UINT64 address = addressDiff + model - > base ( index ) ;
2021-04-04 17:09:23 +08:00
UINT32 base = ( UINT32 ) ( address + model - > header ( index ) . size ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-11-28 00:46:16 +08:00
if ( originalImageBase = = base ) {
2019-01-07 21:05:57 +08:00
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
2019-11-28 00:46:16 +08:00
UINT32 xored = base ^ originalImageBase ; // XOR result can't be zero
2019-01-07 21:05:57 +08:00
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 ;
}
}
}
2022-08-28 18:47:01 +08:00
2019-01-07 21:05:57 +08:00
// Show message if imageBaseType is still unknown
2019-11-28 00:46:16 +08:00
if ( imageBaseType = = EFI_IMAGE_TE_BASE_OTHER ) {
2019-01-07 21:05:57 +08:00
msg ( usprintf ( " %s: TE image base is neither zero, nor original, nor adjusted, nor top-swapped " , __FUNCTION__ ) , index ) ;
2019-11-28 00:46:16 +08:00
}
2022-08-28 18:47:01 +08:00
2019-01-07 21:05:57 +08:00
// Update parsing data
2022-08-28 14:00:05 +08:00
TE_IMAGE_SECTION_PARSING_DATA pdata = { } ;
2019-01-07 21:05:57 +08:00
pdata . imageBaseType = imageBaseType ;
2019-11-28 00:46:16 +08:00
pdata . originalImageBase = originalImageBase ;
2019-01-07 21:05:57 +08:00
pdata . adjustedImageBase = adjustedImageBase ;
model - > setParsingData ( index , UByteArray ( ( const char * ) & pdata , sizeof ( pdata ) ) ) ;
2017-10-12 13:59:23 +08:00
}
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
// Process child items
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2021-04-04 17:09:23 +08:00
checkTeImageBase ( index . model ( ) - > index ( i , 0 , index ) ) ;
2017-10-12 13:59:23 +08:00
}
2022-08-28 18:47:01 +08:00
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 ;
2022-08-28 18:47:01 +08:00
2019-01-07 21:05:57 +08:00
// Add offset
model - > addInfo ( index , usprintf ( " Offset: %Xh \n " , model - > offset ( index ) ) , false ) ;
2022-08-28 18:47:01 +08:00
2019-01-07 21:05:57 +08:00
// Add current base if the element is not compressed
2021-10-07 23:51:39 +08:00
// or it's compressed, but its parent isn't
2017-10-12 13:59:23 +08:00
if ( ( ! model - > compressed ( index ) ) | | ( index . parent ( ) . isValid ( ) & & ! model - > compressed ( index . parent ( ) ) ) ) {
2021-10-07 23:51:39 +08:00
// Add physical address of the whole item or its header and data portions separately
2019-01-07 21:05:57 +08:00
UINT64 address = addressDiff + model - > base ( index ) ;
if ( address < = 0xFFFFFFFFUL ) {
2021-04-04 17:09:23 +08:00
UINT32 headerSize = ( UINT32 ) model - > header ( index ) . size ( ) ;
2019-01-07 21:05:57 +08:00
if ( headerSize ) {
2022-08-29 14:23:38 +08:00
model - > addInfo ( index , usprintf ( " Data address: %08Xh \n " , ( UINT32 ) address + headerSize ) , false ) ;
model - > addInfo ( index , usprintf ( " Header address: %08Xh \n " , ( UINT32 ) address ) , false ) ;
2019-01-07 21:05:57 +08:00
}
else {
2022-08-29 14:23:38 +08:00
model - > addInfo ( index , usprintf ( " Address: %08Xh \n " , ( UINT32 ) address ) , false ) ;
2019-01-07 21:05:57 +08:00
}
}
// 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 ) ;
2022-08-28 18:47:01 +08:00
2016-07-15 03:22:51 +08:00
// Process child items
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2021-04-04 17:09:23 +08:00
addInfoRecursive ( index . model ( ) - > index ( i , 0 , index ) ) ;
2016-07-15 03:22:51 +08:00
}
2022-08-28 18:47:01 +08:00
2016-07-15 03:22:51 +08:00
return U_SUCCESS ;
}
2020-02-09 03:05:33 +08:00
USTATUS FfsParser : : checkProtectedRanges ( const UModelIndex & index )
2017-10-12 13:59:23 +08:00
{
// Sanity check
if ( ! index . isValid ( ) )
return U_INVALID_PARAMETER ;
2022-08-28 18:47:01 +08:00
2022-10-11 15:39:19 +08:00
// QByteArray (Qt builds) supports obtaining data from invalid offsets in QByteArray,
// so mid() here doesn't throw anything for UEFITool, just returns ranges with all zeroes
// UByteArray (non-Qt builds) throws an exception that needs to be caught every time or the tools will crash.
// TODO: add sanity checks everythere so non-Qt UByteArray stuff don't need to throw
2017-10-12 13:59:23 +08:00
// Calculate digest for BG-protected ranges
UByteArray protectedParts ;
bool bgProtectedRangeFound = false ;
2020-04-23 00:25:36 +08:00
try {
2022-08-29 14:23:38 +08:00
for ( UINT32 i = 0 ; i < ( UINT32 ) protectedRanges . size ( ) ; i + + ) {
2022-10-11 15:39:19 +08:00
if ( protectedRanges [ i ] . Type = = PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB
& & protectedRanges [ i ] . Size > 0 ) {
2020-04-23 00:25:36 +08:00
bgProtectedRangeFound = true ;
2022-08-29 14:23:38 +08:00
if ( ( UINT64 ) protectedRanges [ i ] . Offset > = addressDiff ) {
protectedRanges [ i ] . Offset - = ( UINT32 ) addressDiff ;
2020-04-23 00:25:36 +08:00
} else {
2022-08-29 14:23:38 +08:00
msg ( usprintf ( " %s: suspicious protected range offset " , __FUNCTION__ ) , index ) ;
2020-04-23 00:25:36 +08:00
}
2022-08-29 14:23:38 +08:00
protectedParts + = openedImage . mid ( protectedRanges [ i ] . Offset , protectedRanges [ i ] . Size ) ;
markProtectedRangeRecursive ( index , protectedRanges [ i ] ) ;
2020-04-23 00:25:36 +08:00
}
2017-10-12 13:59:23 +08:00
}
2020-04-23 00:25:36 +08:00
} catch ( . . . ) {
bgProtectedRangeFound = false ;
2017-10-12 13:59:23 +08:00
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
if ( bgProtectedRangeFound ) {
2022-08-29 14:23:38 +08:00
UINT8 digest [ SHA512_HASH_SIZE ] = { } ;
UString digestString ;
UString ibbDigests ;
// SHA1
digestString = " " ;
sha1 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest ) ;
for ( UINT8 i = 0 ; i < SHA1_HASH_SIZE ; i + + ) {
digestString + = usprintf ( " %02X " , digest [ i ] ) ;
}
ibbDigests + = UString ( " Computed IBB Hash (SHA1): " ) + digestString + " \n " ;
// SHA256
digestString = " " ;
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest ) ;
for ( UINT8 i = 0 ; i < SHA256_HASH_SIZE ; i + + ) {
digestString + = usprintf ( " %02X " , digest [ i ] ) ;
}
ibbDigests + = UString ( " Computed IBB Hash (SHA256): " ) + digestString + " \n " ;
// SHA384
digestString = " " ;
sha384 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest ) ;
for ( UINT8 i = 0 ; i < SHA384_HASH_SIZE ; i + + ) {
digestString + = usprintf ( " %02X " , digest [ i ] ) ;
}
ibbDigests + = UString ( " Computed IBB Hash (SHA384): " ) + digestString + " \n " ;
// SHA512
digestString = " " ;
sha512 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest ) ;
for ( UINT8 i = 0 ; i < SHA512_HASH_SIZE ; i + + ) {
digestString + = usprintf ( " %02X " , digest [ i ] ) ;
}
ibbDigests + = UString ( " Computed IBB Hash (SHA512): " ) + digestString + " \n " ;
// SM3
digestString = " " ;
sm3 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest ) ;
for ( UINT8 i = 0 ; i < SM3_HASH_SIZE ; i + + ) {
digestString + = usprintf ( " %02X " , digest [ i ] ) ;
}
ibbDigests + = UString ( " Computed IBB Hash (SM3): " ) + digestString + " \n " ;
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
securityInfo + = ibbDigests + " \n " ;
2017-10-12 13:59:23 +08:00
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
// Calculate digests for vendor-protected ranges
2022-08-29 14:23:38 +08:00
for ( UINT32 i = 0 ; i < ( UINT32 ) protectedRanges . size ( ) ; i + + ) {
if ( protectedRanges [ i ] . Type = = PROTECTED_RANGE_VENDOR_HASH_AMI_V1 ) {
if ( ! dxeCore . 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
2022-08-29 14:23:38 +08:00
UModelIndex dxeRootVolumeIndex = model - > findLastParentOfType ( dxeCore , Types : : Volume ) ;
2017-10-12 13:59:23 +08:00
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 {
2022-10-11 15:39:19 +08:00
try {
protectedRanges [ i ] . Offset = model - > base ( dxeRootVolumeIndex ) ;
protectedParts = openedImage . mid ( protectedRanges [ i ] . Offset , protectedRanges [ i ] . Size ) ;
UByteArray digest ( SHA256_HASH_SIZE , ' \x00 ' ) ;
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
if ( digest ! = protectedRanges [ i ] . Hash ) {
msg ( usprintf ( " %s: old AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
protectedRanges [ i ] . Offset , protectedRanges [ i ] . Offset + protectedRanges [ i ] . Size ) ,
model - > findByBase ( protectedRanges [ i ] . Offset ) ) ;
}
markProtectedRangeRecursive ( index , protectedRanges [ i ] ) ;
}
catch ( . . . ) {
// Do nothing, this range is likely not found in the image
2017-12-11 09:56:00 +08:00
}
}
}
}
2022-08-29 14:23:38 +08:00
else if ( protectedRanges [ i ] . Type = = PROTECTED_RANGE_INTEL_BOOT_GUARD_POST_IBB ) {
if ( ! dxeCore . 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
2022-08-29 14:23:38 +08:00
UModelIndex dxeRootVolumeIndex = model - > findLastParentOfType ( dxeCore , Types : : Volume ) ;
2017-12-11 09:56:00 +08:00
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
}
2022-08-28 14:00:05 +08:00
else {
2022-10-11 15:39:19 +08:00
try {
protectedRanges [ i ] . Offset = model - > base ( dxeRootVolumeIndex ) ;
protectedRanges [ i ] . Size = ( UINT32 ) ( model - > header ( dxeRootVolumeIndex ) . size ( ) + model - > body ( dxeRootVolumeIndex ) . size ( ) + model - > tail ( dxeRootVolumeIndex ) . size ( ) ) ;
protectedParts = openedImage . mid ( protectedRanges [ i ] . Offset , protectedRanges [ i ] . Size ) ;
// Calculate the hash
UByteArray digest ( SHA512_HASH_SIZE , ' \x00 ' ) ;
if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SHA1 ) {
sha1 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SHA1_HASH_SIZE ) ;
}
else if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SHA256 ) {
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SHA256_HASH_SIZE ) ;
}
else if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SHA384 ) {
sha384 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SHA384_HASH_SIZE ) ;
}
else if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SHA512 ) {
sha512 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SHA512_HASH_SIZE ) ;
}
else if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SM3 ) {
sm3 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SM3_HASH_SIZE ) ;
}
else {
msg ( usprintf ( " %s: post-IBB protected range [%Xh:%Xh] uses unknown hash algorithm %04Xh " , __FUNCTION__ ,
protectedRanges [ i ] . Offset , protectedRanges [ i ] . Offset + protectedRanges [ i ] . Size , protectedRanges [ i ] . AlgorithmId ) ,
model - > findByBase ( protectedRanges [ i ] . Offset ) ) ;
}
// Check the hash
if ( digest ! = protectedRanges [ i ] . Hash ) {
msg ( usprintf ( " %s: post-IBB protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
protectedRanges [ i ] . Offset , protectedRanges [ i ] . Offset + protectedRanges [ i ] . Size ) ,
model - > findByBase ( protectedRanges [ i ] . Offset ) ) ;
}
markProtectedRangeRecursive ( index , protectedRanges [ i ] ) ;
2022-08-29 14:23:38 +08:00
}
2022-10-11 15:39:19 +08:00
catch ( . . . ) {
// Do nothing, this range is likely not found in the image
2017-10-12 13:59:23 +08:00
}
}
}
}
2022-08-29 14:23:38 +08:00
else if ( protectedRanges [ i ] . Type = = PROTECTED_RANGE_VENDOR_HASH_AMI_V2 ) {
2022-10-11 15:39:19 +08:00
try {
2022-08-29 14:23:38 +08:00
protectedRanges [ i ] . Offset - = ( UINT32 ) addressDiff ;
protectedParts = openedImage . mid ( protectedRanges [ i ] . Offset , protectedRanges [ i ] . Size ) ;
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
UByteArray digest ( SHA256_HASH_SIZE , ' \x00 ' ) ;
2020-09-25 23:16:10 +08:00
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
if ( digest ! = protectedRanges [ i ] . Hash ) {
2020-09-25 23:16:10 +08:00
msg ( usprintf ( " %s: AMI protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
2022-08-29 14:23:38 +08:00
protectedRanges [ i ] . Offset , protectedRanges [ i ] . Offset + protectedRanges [ i ] . Size ) ,
model - > findByBase ( protectedRanges [ i ] . Offset ) ) ;
2020-09-25 23:16:10 +08:00
}
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
markProtectedRangeRecursive ( index , protectedRanges [ i ] ) ;
2022-10-11 15:39:19 +08:00
}
catch ( . . . ) {
// Do nothing, this range is likely not found in the image
2020-09-25 23:16:10 +08:00
}
2017-10-12 13:59:23 +08:00
}
2022-08-29 14:23:38 +08:00
else if ( protectedRanges [ i ] . Type = = PROTECTED_RANGE_VENDOR_HASH_PHOENIX
& & protectedRanges [ i ] . Size ! = 0 & & protectedRanges [ i ] . Size ! = 0xFFFFFFFF
& & protectedRanges [ i ] . Offset ! = 0xFFFFFFFF ) {
2022-10-11 15:39:19 +08:00
try {
protectedRanges [ i ] . Offset + = ( UINT32 ) protectedRegionsBase ;
protectedParts = openedImage . mid ( protectedRanges [ i ] . Offset , protectedRanges [ i ] . Size ) ;
UByteArray digest ( SHA256_HASH_SIZE , ' \x00 ' ) ;
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
if ( digest ! = protectedRanges [ i ] . Hash ) {
msg ( usprintf ( " %s: Phoenix protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
protectedRanges [ i ] . Offset , protectedRanges [ i ] . Offset + protectedRanges [ i ] . Size ) ,
model - > findByBase ( protectedRanges [ i ] . Offset ) ) ;
}
markProtectedRangeRecursive ( index , protectedRanges [ i ] ) ;
}
catch ( . . . ) {
// Do nothing, this range is likely not found in the image
2017-10-12 13:59:23 +08:00
}
2017-11-06 15:10:06 +08:00
}
2022-08-29 14:23:38 +08:00
else if ( protectedRanges [ i ] . Type = = PROTECTED_RANGE_VENDOR_HASH_MICROSOFT_PMDA
& & protectedRanges [ i ] . Size ! = 0 & & protectedRanges [ i ] . Size ! = 0xFFFFFFFF
& & protectedRanges [ i ] . Offset ! = 0 & & protectedRanges [ i ] . Offset ! = 0xFFFFFFFF ) {
2022-10-11 15:39:19 +08:00
try {
protectedRanges [ i ] . Offset - = ( UINT32 ) addressDiff ;
protectedParts = openedImage . mid ( protectedRanges [ i ] . Offset , protectedRanges [ i ] . Size ) ;
// Calculate the hash
UByteArray digest ( SHA512_HASH_SIZE , ' \x00 ' ) ;
if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SHA1 ) {
sha1 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SHA1_HASH_SIZE ) ;
}
else if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SHA256 ) {
sha256 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SHA256_HASH_SIZE ) ;
}
else if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SHA384 ) {
sha384 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SHA384_HASH_SIZE ) ;
}
else if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SHA512 ) {
sha512 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SHA512_HASH_SIZE ) ;
}
else if ( protectedRanges [ i ] . AlgorithmId = = TCG_HASH_ALGORITHM_ID_SM3 ) {
sm3 ( protectedParts . constData ( ) , protectedParts . size ( ) , digest . data ( ) ) ;
digest = digest . left ( SM3_HASH_SIZE ) ;
}
else {
msg ( usprintf ( " %s: Microsoft PMDA protected range [%Xh:%Xh] uses unknown hash algorithm %04Xh " , __FUNCTION__ ,
protectedRanges [ i ] . Offset , protectedRanges [ i ] . Offset + protectedRanges [ i ] . Size , protectedRanges [ i ] . AlgorithmId ) ,
model - > findByBase ( protectedRanges [ i ] . Offset ) ) ;
}
// Check the hash
if ( digest ! = protectedRanges [ i ] . Hash ) {
msg ( usprintf ( " %s: Microsoft PMDA protected range [%Xh:%Xh] hash mismatch, opened image may refuse to boot " , __FUNCTION__ ,
protectedRanges [ i ] . Offset , protectedRanges [ i ] . Offset + protectedRanges [ i ] . Size ) ,
model - > findByBase ( protectedRanges [ i ] . Offset ) ) ;
}
markProtectedRangeRecursive ( index , protectedRanges [ i ] ) ;
2022-08-29 14:23:38 +08:00
}
2022-10-11 15:39:19 +08:00
catch ( . . . ) {
// Do nothing, this range is likely not found in the image
2017-11-06 15:10:06 +08:00
}
2017-10-12 13:59:23 +08:00
}
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
return U_SUCCESS ;
}
2022-08-29 14:23:38 +08:00
USTATUS FfsParser : : markProtectedRangeRecursive ( const UModelIndex & index , const PROTECTED_RANGE & range )
2017-10-12 13:59:23 +08:00
{
if ( ! index . isValid ( ) )
return U_SUCCESS ;
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
// 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 ) ;
2021-04-04 17:09:23 +08:00
UINT32 currentSize = ( UINT32 ) ( model - > header ( index ) . size ( ) + model - > body ( index ) . size ( ) + model - > tail ( index ) . size ( ) ) ;
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
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
2022-08-29 14:23:38 +08:00
if ( range . Type = = PROTECTED_RANGE_INTEL_BOOT_GUARD_IBB ) {
2019-08-20 02:36:02 +08:00
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 ) ;
}
}
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
for ( int i = 0 ; i < model - > rowCount ( index ) ; i + + ) {
2021-04-04 17:09:23 +08:00
markProtectedRangeRecursive ( index . model ( ) - > index ( i , 0 , index ) , range ) ;
2017-10-12 13:59:23 +08:00
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
return U_SUCCESS ;
}
USTATUS FfsParser : : parseVendorHashFile ( const UByteArray & fileGuid , const UModelIndex & index )
{
2022-08-29 14:23:38 +08:00
// Check sanity
if ( ! index . isValid ( ) ) {
return U_INVALID_PARAMETER ;
}
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
if ( fileGuid = = PROTECTED_RANGE_VENDOR_HASH_FILE_GUID_PHOENIX ) {
2020-01-25 06:15:18 +08:00
const UByteArray & body = model - > body ( index ) ;
UINT32 size = ( UINT32 ) body . size ( ) ;
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
// File too small to have even a signature
2022-08-29 14:23:38 +08:00
if ( size < sizeof ( UINT64 ) ) {
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 ;
}
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
const PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_PHOENIX * header = ( const PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_PHOENIX * ) body . constData ( ) ;
2017-10-12 13:59:23 +08:00
if ( header - > Signature = = BG_VENDOR_HASH_FILE_SIGNATURE_PHOENIX ) {
2022-08-29 14:23:38 +08:00
if ( size < sizeof ( PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_PHOENIX ) | |
size < sizeof ( PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_PHOENIX ) + header - > NumEntries * sizeof ( PROTECTED_RANGE_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 ;
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
if ( header - > NumEntries > 0 ) {
bool protectedRangesFound = false ;
for ( UINT32 i = 0 ; i < header - > NumEntries ; i + + ) {
protectedRangesFound = true ;
2022-08-29 14:23:38 +08:00
const PROTECTED_RANGE_VENDOR_HASH_FILE_ENTRY * entry = ( const PROTECTED_RANGE_VENDOR_HASH_FILE_ENTRY * ) ( header + 1 ) + i ;
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
PROTECTED_RANGE range = { } ;
range . Offset = entry - > Base ;
2017-10-12 13:59:23 +08:00
range . Size = entry - > Size ;
2022-08-29 14:23:38 +08:00
range . AlgorithmId = TCG_HASH_ALGORITHM_ID_SHA256 ;
2017-10-12 13:59:23 +08:00
range . Hash = UByteArray ( ( const char * ) entry - > Hash , sizeof ( entry - > Hash ) ) ;
2022-08-29 14:23:38 +08:00
range . Type = PROTECTED_RANGE_VENDOR_HASH_PHOENIX ;
protectedRanges . push_back ( range ) ;
2017-10-12 13:59:23 +08:00
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
if ( protectedRangesFound ) {
2022-10-09 17:24:27 +08:00
securityInfo + = usprintf ( " Phoenix hash file found at base %08Xh \n Protected ranges: \n " , model - > base ( index ) ) ;
2017-10-12 13:59:23 +08:00
for ( UINT32 i = 0 ; i < header - > NumEntries ; i + + ) {
2022-08-29 14:23:38 +08:00
const PROTECTED_RANGE_VENDOR_HASH_FILE_ENTRY * entry = ( const PROTECTED_RANGE_VENDOR_HASH_FILE_ENTRY * ) ( header + 1 ) + i ;
securityInfo + = usprintf ( " RelativeOffset: %08Xh Size: %Xh \n Hash: " , entry - > Base , 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
}
2022-08-29 14:23:38 +08:00
securityInfo + = " \n " ;
2017-10-12 13:59:23 +08:00
}
2022-08-29 14:23:38 +08:00
securityInfo + = " \n " ;
2017-10-12 13:59:23 +08:00
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
model - > setText ( index , UString ( " Phoenix hash file " ) ) ;
}
}
2022-08-29 14:23:38 +08:00
else if ( fileGuid = = PROTECTED_RANGE_VENDOR_HASH_FILE_GUID_AMI ) {
2017-10-12 13:59:23 +08:00
UModelIndex fileIndex = model - > parent ( index ) ;
2020-01-25 06:15:18 +08:00
const UByteArray & body = model - > body ( index ) ;
UINT32 size = ( UINT32 ) body . size ( ) ;
if ( size ! = ( UINT32 ) body . count ( ' \xFF ' ) ) {
2022-08-29 14:23:38 +08:00
if ( size = = sizeof ( PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_AMI_V2 ) ) {
const PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_AMI_V2 * entry = ( const PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_AMI_V2 * ) ( body . constData ( ) ) ;
securityInfo + = usprintf ( " AMI hash file v2 found at base %08Xh \n Protected ranges: " , model - > base ( fileIndex ) ) ;
securityInfo + = usprintf ( " \n Address: %08Xh, Size: %Xh \n Hash (SHA256): " , entry - > Hash0 . Base , entry - > Hash0 . Size ) ;
for ( UINT8 j = 0 ; j < sizeof ( entry - > Hash0 . Hash ) ; j + + ) {
securityInfo + = usprintf ( " %02X " , entry - > Hash0 . Hash [ j ] ) ;
}
securityInfo + = usprintf ( " \n Address: %08Xh, Size: %Xh \n Hash (SHA256): " , entry - > Hash1 . Base , entry - > Hash1 . Size ) ;
for ( UINT8 j = 0 ; j < sizeof ( entry - > Hash1 . Hash ) ; j + + ) {
securityInfo + = usprintf ( " %02X " , entry - > Hash1 . Hash [ j ] ) ;
2017-10-12 13:59:23 +08:00
}
2022-08-29 14:23:38 +08:00
securityInfo + = " \n " ;
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
if ( entry - > Hash0 . Base ! = 0 & & entry - > Hash0 . Size ! = 0
& & entry - > Hash0 . Base ! = 0xFFFFFFFF & & entry - > Hash0 . Size ! = 0xFFFFFFFF ) {
PROTECTED_RANGE range = { } ;
range . Offset = entry - > Hash0 . Base ;
range . Size = entry - > Hash0 . Size ;
range . AlgorithmId = TCG_HASH_ALGORITHM_ID_SHA256 ;
range . Hash = UByteArray ( ( const char * ) entry - > Hash0 . Hash , sizeof ( entry - > Hash0 . Hash ) ) ;
range . Type = PROTECTED_RANGE_VENDOR_HASH_AMI_V2 ;
protectedRanges . push_back ( range ) ;
2017-10-12 13:59:23 +08:00
}
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
if ( entry - > Hash1 . Base ! = 0 & & entry - > Hash1 . Size ! = 0
& & entry - > Hash1 . Base ! = 0xFFFFFFFF & & entry - > Hash1 . Size ! = 0xFFFFFFFF ) {
PROTECTED_RANGE range = { } ;
range . Offset = entry - > Hash1 . Base ;
range . Size = entry - > Hash1 . Size ;
range . AlgorithmId = TCG_HASH_ALGORITHM_ID_SHA256 ;
range . Hash = UByteArray ( ( const char * ) entry - > Hash1 . Hash , sizeof ( entry - > Hash1 . Hash ) ) ;
range . Type = PROTECTED_RANGE_VENDOR_HASH_AMI_V2 ;
protectedRanges . push_back ( range ) ;
}
2022-10-09 17:24:27 +08:00
msg ( usprintf ( " %s: AMI hash file v2 found " , __FUNCTION__ ) , fileIndex ) ;
2017-10-12 13:59:23 +08:00
}
2022-08-29 14:23:38 +08:00
else if ( size = = sizeof ( PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_AMI_V1 ) ) {
securityInfo + = usprintf ( " AMI hash file v1 found at base %08Xh \n Protected range: \n " , model - > base ( fileIndex ) ) ;
const PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_AMI_V1 * entry = ( const PROTECTED_RANGE_VENDOR_HASH_FILE_HEADER_AMI_V1 * ) ( body . constData ( ) ) ;
securityInfo + = usprintf ( " Size: %Xh \n Hash (SHA256): " , 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
}
2022-08-29 14:23:38 +08:00
securityInfo + = " \n \n " ;
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
if ( entry - > Size ! = 0 & & entry - > Size ! = 0xFFFFFFFF ) {
PROTECTED_RANGE range = { } ;
range . Offset = 0 ;
range . Size = entry - > Size ;
range . AlgorithmId = TCG_HASH_ALGORITHM_ID_SHA256 ;
range . Hash = UByteArray ( ( const char * ) entry - > Hash , sizeof ( entry - > Hash ) ) ;
range . Type = PROTECTED_RANGE_VENDOR_HASH_AMI_V1 ;
protectedRanges . push_back ( range ) ;
}
2022-08-28 18:47:01 +08:00
2022-10-09 17:24:27 +08:00
msg ( usprintf ( " %s: AMI hash file v1 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
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
model - > setText ( fileIndex , UString ( " AMI hash file " ) ) ;
}
2022-08-28 18:47:01 +08:00
2017-10-12 13:59:23 +08:00
return U_SUCCESS ;
}
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 ;
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
while ( true ) {
// Parse current microcode
UModelIndex currentMicrocode ;
UByteArray ucode = model - > body ( index ) . mid ( offset ) ;
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
// 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 ) ;
}
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
// Add the rest as padding
if ( result ) {
if ( offset < bodySize ) {
// Get info
UString name = UString ( " Padding " ) ;
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) ucode . size ( ) , ( UINT32 ) ucode . size ( ) ) ;
2018-10-08 17:58:12 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
const INTEL_MICROCODE_HEADER * ucodeHeader = ( const INTEL_MICROCODE_HEADER * ) microcode . constData ( ) ;
2022-08-28 18:47:01 +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 ;
}
2022-08-28 18:47:01 +08:00
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 ;
}
2022-08-28 18:47:01 +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
}
2022-08-28 18:47:01 +08:00
2020-02-09 03:05:33 +08:00
// Cross check DataSize and TotalSize
if ( ucodeHeader - > TotalSize < sizeof ( INTEL_MICROCODE_HEADER ) + dataSize ) {
return U_INVALID_MICROCODE ;
}
2022-08-28 18:47:01 +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 ) ;
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
// 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 ) ;
2020-02-09 03:05:33 +08:00
UByteArray tail ;
2022-08-28 18:47:01 +08:00
2020-02-09 03:05:33 +08:00
// Check if the tail is present
if ( ucodeHeader - > TotalSize > sizeof ( INTEL_MICROCODE_HEADER ) + dataSize ) {
tail = microcode . mid ( sizeof ( INTEL_MICROCODE_HEADER ) + dataSize , ucodeHeader - > TotalSize - ( sizeof ( INTEL_MICROCODE_HEADER ) + dataSize ) ) ;
}
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
// Check if we have extended header in the tail
UString extendedHeaderInfo ;
2020-02-09 03:05:33 +08:00
bool msgUnknownOrDamagedMicrocodeTail = false ;
2019-07-25 01:30:59 +08:00
if ( ( UINT32 ) tail . size ( ) > = sizeof ( INTEL_MICROCODE_EXTENDED_HEADER ) ) {
const INTEL_MICROCODE_EXTENDED_HEADER * extendedHeader = ( const INTEL_MICROCODE_EXTENDED_HEADER * ) tail . constData ( ) ;
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
// 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 ;
}
}
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
// We have more than 0 entries and they are all in the tail
if ( extendedReservedBytesValid
& & extendedHeader - > EntryCount > 0
2020-02-09 03:05:33 +08:00
& & ( UINT32 ) tail . size ( ) = = sizeof ( INTEL_MICROCODE_EXTENDED_HEADER ) + extendedHeader - > EntryCount * sizeof ( INTEL_MICROCODE_EXTENDED_HEADER_ENTRY ) ) {
2019-07-25 01:30:59 +08:00
// 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 ) ) ;
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
extendedHeaderInfo = usprintf ( " \n Extended header entries: %u \n Extended header checksum: %08Xh, " ,
extendedHeader - > EntryCount ,
extendedHeader - > Checksum )
2022-08-28 18:47:01 +08:00
+ ( extendedHeader - > Checksum = = extendedCalculated ? UString ( " valid " ) : usprintf ( " invalid, should be %08Xh " , extendedCalculated ) ) ;
2019-07-25 01:30:59 +08:00
const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY * firstEntry = ( const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY * ) ( extendedHeader + 1 ) ;
2022-09-10 19:59:23 +08:00
for ( UINT32 i = 0 ; i < extendedHeader - > EntryCount ; i + + ) {
2019-07-25 01:30:59 +08:00
const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY * entry = ( const INTEL_MICROCODE_EXTENDED_HEADER_ENTRY * ) ( firstEntry + i ) ;
2022-08-28 18:47:01 +08:00
2019-07-25 01:30:59 +08:00
// 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 ) ;
2022-08-28 18:47:01 +08:00
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 )
2022-08-28 18:47:01 +08:00
+ ( entry - > Checksum = = entryCalculated ? UString ( " valid " ) : usprintf ( " invalid, should be %08Xh " , entryCalculated ) ) ;
2019-07-25 01:30:59 +08:00
}
}
2020-02-09 03:05:33 +08:00
else {
msgUnknownOrDamagedMicrocodeTail = true ;
}
}
else if ( tail . size ( ) ! = 0 ) {
msgUnknownOrDamagedMicrocodeTail = true ;
2019-07-25 01:30:59 +08:00
}
2022-08-28 18:47:01 +08:00
2020-02-09 03:05:33 +08:00
// Get microcode binary
UByteArray microcodeBinary = microcode . left ( ucodeHeader - > TotalSize ) ;
2022-08-28 18:47:01 +08:00
2018-10-08 17:58:12 +08:00
// Add info
UString name ( " Intel microcode " ) ;
2022-08-28 18:01:43 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n Header size: 0h (0u) \n Body size: %Xh (%u) \n Tail size: 0h (0u) \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, " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) microcodeBinary . size ( ) , ( UINT32 ) microcodeBinary . size ( ) ,
( UINT32 ) microcodeBinary . size ( ) , ( UINT32 ) microcodeBinary . size ( ) ,
2019-07-25 01:30:59 +08:00
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 )
2022-08-28 18:47:01 +08:00
+ ( ucodeHeader - > Checksum = = calculated ? UString ( " valid " ) : usprintf ( " invalid, should be %08Xh " , calculated ) )
+ extendedHeaderInfo ;
2018-10-08 17:58:12 +08:00
// Add tree item
2020-02-09 03:05:33 +08:00
index = model - > addItem ( localOffset , Types : : Microcode , Subtypes : : IntelMicrocode , name , UString ( ) , info , UByteArray ( ) , microcodeBinary , UByteArray ( ) , Fixed , parent ) ;
2019-07-25 01:30:59 +08:00
if ( msgInvalidChecksum )
msg ( usprintf ( " %s: invalid microcode checksum %08Xh, should be %08Xh " , __FUNCTION__ , ucodeHeader - > Checksum , calculated ) , index ) ;
2020-02-09 03:05:33 +08:00
if ( msgUnknownOrDamagedMicrocodeTail )
2022-08-28 18:47:01 +08:00
msg ( usprintf ( " %s: extended header of size %Xh (%u) found, but it's damaged or has unknown format " , __FUNCTION__ , ( UINT32 ) tail . size ( ) , ( UINT32 ) tail . size ( ) ) , index ) ;
2019-07-25 01:30:59 +08:00
// 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 ( ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Populate partition table header
const BPDT_HEADER * ptHeader = ( const BPDT_HEADER * ) ( region . constData ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
UByteArray header = region . left ( sizeof ( BPDT_HEADER ) ) ;
UByteArray body = region . mid ( sizeof ( BPDT_HEADER ) , ptBodySize ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
UString name = UString ( " BPDT partition table " ) ;
2022-10-09 13:18:28 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n "
" Number of entries: %u \n Version: %02Xh \n RedundancyFlag: %Xh \n "
2019-08-20 02:36:02 +08:00
" IFWI version: %Xh \n FITC version: %u.%u.%u.%u " ,
ptSize , ptSize ,
2022-08-28 18:47:01 +08:00
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
2019-08-20 02:36:02 +08:00
ptBodySize , ptBodySize ,
ptHeader - > NumEntries ,
ptHeader - > HeaderVersion ,
2022-10-09 13:18:28 +08:00
ptHeader - > RedundancyFlag ,
2019-08-20 02:36:02 +08:00
ptHeader - > IfwiVersion ,
ptHeader - > FitcMajor , ptHeader - > FitcMinor , ptHeader - > FitcHotfix , ptHeader - > FitcBuild ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Add tree item
index = model - > addItem ( localOffset , Types : : BpdtStore , 0 , name , UString ( ) , info , header , body , UByteArray ( ) , Fixed , parent ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Adjust offset
UINT32 offset = sizeof ( BPDT_HEADER ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Add partition table entries
std : : vector < BPDT_PARTITION_INFO > partitions ;
const BPDT_ENTRY * firstPtEntry = ( const BPDT_ENTRY * ) ( ( const UINT8 * ) ptHeader + sizeof ( BPDT_HEADER ) ) ;
2022-08-25 12:49:10 +08:00
UINT16 numEntries = ptHeader - > NumEntries ;
for ( UINT16 i = 0 ; i < numEntries ; i + + ) {
2019-08-20 02:36:02 +08:00
// Populate entry header
const BPDT_ENTRY * ptEntry = firstPtEntry + i ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
name = bpdtEntryTypeToUString ( ptEntry - > Type ) ;
2022-08-29 13:08:45 +08:00
info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh \n Partition offset: %Xh \n Partition length: %Xh " ,
( UINT32 ) sizeof ( BPDT_ENTRY ) , ( UINT32 ) sizeof ( BPDT_ENTRY ) ,
2019-08-20 02:36:02 +08:00
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 " ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Adjust offset
offset + = sizeof ( BPDT_ENTRY ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
if ( ptEntry - > Offset ! = 0 & & ptEntry - > Offset ! = 0xFFFFFFFF & & ptEntry - > Size ! = 0 ) {
// Add to partitions vector
2022-08-25 12:49:10 +08:00
BPDT_PARTITION_INFO partition = { } ;
2019-08-20 02:36:02 +08:00
partition . type = Types : : BpdtPartition ;
partition . ptEntry = * ptEntry ;
partition . ptEntry . Offset - = sbpdtOffsetFixup ;
partition . index = entryIndex ;
partitions . push_back ( partition ) ;
}
}
2022-08-28 18:47:01 +08:00
2022-09-13 15:45:40 +08:00
// Check for empty set of partitions
if ( partitions . empty ( ) ) {
// Add a single padding partition in this case
BPDT_PARTITION_INFO padding = { } ;
padding . ptEntry . Offset = offset ;
padding . ptEntry . Size = ( UINT32 ) ( region . size ( ) - padding . ptEntry . Offset ) ;
padding . type = Types : : Padding ;
partitions . push_back ( padding ) ;
2019-08-20 02:36:02 +08:00
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
make_partition_table_consistent :
// Sort partitions by offset
std : : sort ( partitions . begin ( ) , partitions . end ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Check for intersections and paddings between partitions
2022-08-25 12:49:10 +08:00
BPDT_PARTITION_INFO padding = { } ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 {
2021-10-07 23:51:39 +08:00
msg ( usprintf ( " %s: BPDT partition can't fit into its region, truncated " , __FUNCTION__ ) , partitions [ i ] . index ) ;
2019-08-20 02:36:02 +08:00
partitions [ i ] . ptEntry . Size = regionSize - ( UINT32 ) partitions [ i ] . ptEntry . Offset ;
}
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ;
}
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ;
}
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-28 18:01:43 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) ,
2019-08-20 02:36:02 +08:00
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 " ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
UString text = bpdtEntryTypeToUString ( partitions [ i ] . ptEntry . Type ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Add tree item
UModelIndex partitionIndex = model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset , Types : : BpdtPartition , 0 , name , text , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Special case of S-BPDT
2022-10-09 13:18:28 +08:00
if ( partitions [ i ] . ptEntry . Type = = BPDT_ENTRY_TYPE_S_BPDT ) {
2019-08-20 02:36:02 +08:00
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
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Parse code partitions
if ( readUnaligned ( ( const UINT32 * ) partition . constData ( ) ) = = CPD_SIGNATURE ) {
// Parse code partition contents
UModelIndex cpdIndex ;
2021-10-14 08:34:38 +08:00
parseCpdRegion ( partition , 0 , partitionIndex , cpdIndex ) ;
2019-08-20 02:36:02 +08:00
}
2022-08-28 18:47:01 +08:00
2022-10-09 13:18:28 +08:00
// Check for entry type to be known
if ( partitions [ i ] . ptEntry . Type > BPDT_ENTRY_TYPE_PSEP ) {
2019-08-20 02:36:02 +08:00
msg ( usprintf ( " %s: BPDT entry of unknown type found " , __FUNCTION__ ) , partitionIndex ) ;
}
}
else if ( partitions [ i ] . type = = Types : : Padding ) {
2020-11-23 12:56:51 +08:00
UByteArray padding = region . mid ( partitions [ i ] . ptEntry . Offset , partitions [ i ] . ptEntry . Size ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
name = UString ( " Padding " ) ;
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) padding . size ( ) , ( UINT32 ) padding . size ( ) ) ;
2019-08-20 02:36:02 +08:00
// Add tree item
2020-11-23 12:56:51 +08:00
model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset , Types : : Padding , getPaddingType ( padding ) , name , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , parent ) ;
2019-08-20 02:36:02 +08:00
}
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Add padding after the last region
if ( ( UINT64 ) partitions . back ( ) . ptEntry . Offset + ( UINT64 ) partitions . back ( ) . ptEntry . Size < regionSize ) {
2020-11-23 12:56:51 +08:00
UINT64 usedSize = ( UINT64 ) partitions . back ( ) . ptEntry . Offset + ( UINT64 ) partitions . back ( ) . ptEntry . Size ;
UByteArray padding = region . mid ( partitions . back ( ) . ptEntry . Offset + partitions . back ( ) . ptEntry . Size , ( int ) ( regionSize - usedSize ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
name = UString ( " Padding " ) ;
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) padding . size ( ) , ( UINT32 ) padding . size ( ) ) ;
2019-08-20 02:36:02 +08:00
// Add tree item
2020-11-23 12:56:51 +08:00
model - > addItem ( localOffset + partitions . back ( ) . ptEntry . Offset + partitions . back ( ) . ptEntry . Size , Types : : Padding , getPaddingType ( padding ) , name , UString ( ) , info , UByteArray ( ) , padding , UByteArray ( ) , Fixed , parent ) ;
2019-08-20 02:36:02 +08:00
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
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 ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Populate partition table header
const CPD_REV1_HEADER * cpdHeader = ( const CPD_REV1_HEADER * ) region . constData ( ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
ptHeaderSize = sizeof ( CPD_REV2_HEADER ) ;
}
else if ( cpdHeader - > HeaderVersion = = 1 ) {
ptHeaderSize = sizeof ( CPD_REV1_HEADER ) ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
UByteArray header = region . left ( ptHeaderSize ) ;
2021-10-14 08:34:38 +08:00
UByteArray body = region . mid ( ptHeaderSize , ptBodySize ) ;
2019-08-20 02:36:02 +08:00
UString name = usprintf ( " CPD partition table " ) ;
2022-08-28 18:01:43 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Number of entries: %u \n "
2021-10-14 08:34:38 +08:00
" Header version: %u \n Entry version: %u " ,
ptSize , ptSize ,
2022-08-28 18:47:01 +08:00
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
( UINT32 ) body . size ( ) , ( UINT32 ) body . size ( ) ,
2019-08-20 02:36:02 +08:00
cpdHeader - > NumEntries ,
cpdHeader - > HeaderVersion ,
cpdHeader - > EntryVersion ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Add tree item
index = model - > addItem ( localOffset , Types : : CpdStore , 0 , name , UString ( ) , info , header , body , UByteArray ( ) , Fixed , parent ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
2021-10-07 23:51:39 +08:00
name = usprintf ( " %.12s " , cpdEntry - > EntryName ) ;
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) \n Entry offset: %Xh \n Entry length: %Xh \n Huffman compressed: " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) entry . size ( ) , ( UINT32 ) entry . size ( ) ,
2019-08-20 02:36:02 +08:00
cpdEntry - > Offset . Offset ,
cpdEntry - > Length )
+ ( cpdEntry - > Offset . HuffmanCompressed ? " Yes " : " No " ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Add tree item
UModelIndex entryIndex = model - > addItem ( offset , Types : : CpdEntry , 0 , name , UString ( ) , info , UByteArray ( ) , entry , UByteArray ( ) , Fixed , index ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Adjust offset
offset + = sizeof ( CPD_ENTRY ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
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 ;
2021-10-07 23:51:39 +08:00
partition . hasMetaData = false ;
2019-08-20 02:36:02 +08:00
partitions . push_back ( partition ) ;
}
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Add padding if there's no partions to add
if ( partitions . size ( ) = = 0 ) {
UByteArray partition = region . mid ( ptSize ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
name = UString ( " Padding " ) ;
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) ) ;
2019-08-20 02:36:02 +08:00
// Add tree item
model - > addItem ( localOffset + ptSize , Types : : Padding , getPaddingType ( partition ) , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
return U_SUCCESS ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Sort partitions by offset
std : : sort ( partitions . begin ( ) , partitions . end ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Because lenghts for all Huffmann-compressed partitions mean nothing at all, we need to split all partitions into 2 classes:
2021-10-14 08:34:38 +08:00
// 1. CPD manifest
// 2. Metadata entries
2021-10-07 23:51:39 +08:00
UINT32 i = 1 ; // manifest is index 0, .met partitions start at index 1
2019-08-20 02:36:02 +08:00
while ( i < partitions . size ( ) ) {
2021-10-07 23:51:39 +08:00
name = usprintf ( " %.12s " , partitions [ i ] . ptEntry . EntryName ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Check if the current entry is metadata entry
2021-10-07 23:51:39 +08:00
if ( ! name . endsWith ( " .met " ) ) {
2019-08-20 02:36:02 +08:00
// No need to parse further, all metadata partitions are parsed
break ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Search down for corresponding code partition
2021-10-07 23:51:39 +08:00
// Construct its name by removing the .met suffix
name . chop ( 4 ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Search
2021-10-07 23:51:39 +08:00
bool found = false ;
2021-10-14 08:34:38 +08:00
UINT32 j = 1 ;
2019-08-20 02:36:02 +08:00
while ( j < partitions . size ( ) ) {
2021-10-07 23:51:39 +08:00
UString namej = usprintf ( " %.12s " , partitions [ j ] . ptEntry . EntryName ) ;
2022-08-28 18:47:01 +08:00
2021-10-07 23:51:39 +08:00
if ( name = = namej ) {
found = true ;
// Found it, update its Length if needed
2019-08-20 02:36:02 +08:00
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
}
2021-10-07 23:51:39 +08:00
partitions [ j ] . hasMetaData = true ;
2019-08-20 02:36:02 +08:00
// No need to search further
break ;
}
// Check the next partition
j + + ;
}
2021-10-07 23:51:39 +08:00
if ( ! found ) {
msg ( usprintf ( " %s: no code partition " , __FUNCTION__ ) , partitions [ i ] . index ) ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Check the next partition
i + + ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
make_partition_table_consistent :
// Sort partitions by offset
std : : sort ( partitions . begin ( ) , partitions . end ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Check for intersections and paddings between partitions
2022-08-25 15:43:18 +08:00
CPD_PARTITION_INFO padding = { } ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 {
2021-10-07 23:51:39 +08:00
if ( ! partitions [ i ] . hasMetaData & & partitions [ i ] . ptEntry . Offset . HuffmanCompressed ) {
msg ( usprintf ( " %s: CPD partition is compressed but doesn't have metadata and can't fit into its region, length adjusted " , __FUNCTION__ ) ,
partitions [ i ] . index ) ;
}
else {
msg ( usprintf ( " %s: CPD partition can't fit into its region, truncated " , __FUNCTION__ ) , partitions [ i ] . index ) ;
}
2019-08-20 02:36:02 +08:00
partitions [ i ] . ptEntry . Length = ( UINT32 ) region . size ( ) - ( UINT32 ) partitions [ i ] . ptEntry . Offset . Offset ;
}
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Check for intersection with previous partition
if ( partitions [ i ] . ptEntry . Offset . Offset < previousPartitionEnd ) {
2021-10-07 23:51:39 +08:00
// Check if previous partition was compressed but did not have metadata
if ( ! partitions [ i - 1 ] . hasMetaData & & partitions [ i - 1 ] . ptEntry . Offset . HuffmanCompressed ) {
msg ( usprintf ( " %s: CPD partition is compressed but doesn't have metadata, length adjusted " , __FUNCTION__ ) ,
partitions [ i - 1 ] . index ) ;
partitions [ i - 1 ] . ptEntry . Length = ( UINT32 ) partitions [ i ] . ptEntry . Offset . Offset - ( UINT32 ) partitions [ i - 1 ] . ptEntry . Offset . Offset ;
goto make_partition_table_consistent ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
2021-10-07 23:51:39 +08:00
name = usprintf ( " %.12s " , partitions [ i ] . ptEntry . EntryName ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// It's a manifest
2021-10-14 08:34:38 +08:00
if ( name . endsWith ( " .man " ) ) {
2019-08-20 02:36:02 +08:00
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 ) ) ;
2021-10-14 08:34:38 +08:00
UByteArray body = partition . mid ( manifestHeader - > HeaderLength * sizeof ( UINT32 ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) "
2022-08-29 13:08:45 +08:00
" \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) " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) ,
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
( UINT32 ) body . size ( ) , ( UINT32 ) body . size ( ) ,
2021-10-14 08:34:38 +08:00
manifestHeader - > HeaderType ,
2022-08-29 13:08:45 +08:00
manifestHeader - > HeaderLength * ( UINT32 ) sizeof ( UINT32 ) , manifestHeader - > HeaderLength * ( UINT32 ) sizeof ( UINT32 ) ,
2021-10-14 08:34:38 +08:00
manifestHeader - > HeaderVersion ,
manifestHeader - > Flags ,
manifestHeader - > Vendor ,
manifestHeader - > Date ,
2022-08-29 13:08:45 +08:00
manifestHeader - > Size * ( UINT32 ) sizeof ( UINT32 ) , manifestHeader - > Size * ( UINT32 ) sizeof ( UINT32 ) ,
2021-10-14 08:34:38 +08:00
manifestHeader - > VersionMajor , manifestHeader - > VersionMinor , manifestHeader - > VersionBugfix , manifestHeader - > VersionBuild ,
manifestHeader - > SecurityVersion ,
2022-08-29 13:08:45 +08:00
manifestHeader - > ModulusSize * ( UINT32 ) sizeof ( UINT32 ) , manifestHeader - > ModulusSize * ( UINT32 ) sizeof ( UINT32 ) ,
manifestHeader - > ExponentSize * ( UINT32 ) sizeof ( UINT32 ) , manifestHeader - > ExponentSize * ( UINT32 ) sizeof ( UINT32 ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Parse data as extensions area
parseCpdExtensionsArea ( partitionIndex ) ;
}
}
}
// It's a metadata
2021-10-14 08:34:38 +08:00
else if ( name . endsWith ( " .met " ) ) {
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) \n Huffman compressed: " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) )
2019-08-20 02:36:02 +08:00
+ ( partitions [ i ] . ptEntry . Offset . HuffmanCompressed ? " Yes " : " No " ) ;
2022-08-28 18:47:01 +08:00
2021-10-07 23:51:39 +08:00
// Calculate SHA256 hash over the metadata and add it to its info
2022-08-29 14:23:38 +08:00
UByteArray hash ( SHA256_HASH_SIZE , ' \x00 ' ) ;
2019-08-20 02:36:02 +08:00
sha256 ( partition . constData ( ) , partition . size ( ) , hash . data ( ) ) ;
info + = UString ( " \n Metadata hash: " ) + UString ( hash . toHex ( ) . constData ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Parse data as extensions area
parseCpdExtensionsArea ( partitionIndex ) ;
}
// It's a code
else {
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) \n Huffman compressed: " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) )
2019-08-20 02:36:02 +08:00
+ ( partitions [ i ] . ptEntry . Offset . HuffmanCompressed ? " Yes " : " No " ) ;
2022-08-28 18:47:01 +08:00
2021-10-07 23:51:39 +08:00
// Calculate SHA256 hash over the code and add it to its info
2022-08-29 14:23:38 +08:00
UByteArray hash ( SHA256_HASH_SIZE , ' \x00 ' ) ;
2019-08-20 02:36:02 +08:00
sha256 ( partition . constData ( ) , partition . size ( ) , hash . data ( ) ) ;
info + = UString ( " \n Hash: " ) + UString ( hash . toHex ( ) . constData ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
UModelIndex codeIndex = model - > addItem ( localOffset + partitions [ i ] . ptEntry . Offset . Offset , Types : : CpdPartition , Subtypes : : CodeCpdPartition , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , parent ) ;
2022-09-10 20:32:10 +08:00
( void ) parseRawArea ( codeIndex ) ;
2019-08-20 02:36:02 +08:00
}
}
else if ( partitions [ i ] . type = = Types : : Padding ) {
UByteArray partition = region . mid ( partitions [ i ] . ptEntry . Offset . Offset , partitions [ i ] . ptEntry . Length ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Get info
name = UString ( " Padding " ) ;
2022-08-28 18:47:01 +08:00
info = usprintf ( " Full size: %Xh (%u) " , ( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) ) ;
2019-08-20 02:36:02 +08:00
// 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 ;
}
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
return U_SUCCESS ;
}
USTATUS FfsParser : : parseCpdExtensionsArea ( const UModelIndex & index )
{
if ( ! index . isValid ( ) ) {
return U_INVALID_PARAMETER ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
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 ) ;
2022-08-29 14:23:38 +08:00
if ( extHeader - > Length > 0
& & extHeader - > Length < = ( ( UINT32 ) body . size ( ) - offset ) ) {
2019-08-20 02:36:02 +08:00
UByteArray partition = body . mid ( offset , extHeader - > Length ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
UString name = cpdExtensionTypeToUstring ( extHeader - > Type ) ;
2022-08-28 18:47:01 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh " , ( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) , extHeader - > Type ) ;
2019-08-20 02:36:02 +08:00
// 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 ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
const CPD_EXT_SIGNED_PACKAGE_INFO * infoHeader = ( const CPD_EXT_SIGNED_PACKAGE_INFO * ) header . constData ( ) ;
2022-08-28 18:47:01 +08:00
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) \n Header size: %Xh (%u) \n Body size: %Xh (%u) \n Type: %Xh \n "
2021-10-07 23:51:39 +08:00
" Package name: %.4s \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%02X%02X " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) ,
( UINT32 ) header . size ( ) , ( UINT32 ) header . size ( ) ,
( UINT32 ) body . size ( ) , ( UINT32 ) body . size ( ) ,
2019-08-20 02:36:02 +08:00
infoHeader - > ExtensionType ,
2021-10-07 23:51:39 +08:00
infoHeader - > PackageName ,
2019-08-20 02:36:02 +08:00
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 ] ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ( ) ;
2021-10-14 08:34:38 +08:00
// Check HashSize to be sane.
UINT32 hashSize = attrHeader - > HashSize ;
bool msgHashSizeMismatch = false ;
if ( hashSize > sizeof ( attrHeader - > CompletePartitionHash ) ) {
hashSize = sizeof ( attrHeader - > CompletePartitionHash ) ;
msgHashSizeMismatch = true ;
}
2019-08-20 02:36:02 +08:00
// This hash is stored reversed
// Need to reverse it back to normal
2021-10-14 08:34:38 +08:00
UByteArray hash ( ( const char * ) & attrHeader - > CompletePartitionHash , hashSize ) ;
2019-08-20 02:36:02 +08:00
std : : reverse ( hash . begin ( ) , hash . end ( ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh \n "
2021-10-07 23:51:39 +08:00
" Partition name: %.4s \n Partition length: %Xh \n Partition version major: %Xh \n Partition version minor: %Xh \n "
2019-08-20 02:36:02 +08:00
" Data format version: %Xh \n Instance ID: %Xh \n Hash algorithm: %Xh \n Hash size: %Xh \n Action on update: %Xh " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) ,
2019-08-20 02:36:02 +08:00
attrHeader - > ExtensionType ,
2021-10-07 23:51:39 +08:00
attrHeader - > PartitionName ,
2019-08-20 02:36:02 +08:00
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 ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// Add tree item
extIndex = model - > addItem ( offset , Types : : CpdExtension , 0 , name , UString ( ) , info , UByteArray ( ) , partition , UByteArray ( ) , Fixed , index ) ;
2021-10-14 08:34:38 +08:00
if ( msgHashSizeMismatch ) {
2022-08-29 13:08:45 +08:00
msg ( usprintf ( " %s: IFWI Partition Manifest hash size is %u, maximum allowed is %u, truncated " , __FUNCTION__ , attrHeader - > HashSize , ( UINT32 ) sizeof ( attrHeader - > CompletePartitionHash ) ) , extIndex ) ;
2021-10-07 23:51:39 +08:00
}
2019-08-20 02:36:02 +08:00
}
// 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 ( ) ;
2022-08-28 18:47:01 +08:00
int hashSize = ( UINT32 ) partition . size ( ) - CpdExtModuleImageHashOffset ;
2019-08-20 02:36:02 +08:00
// This hash is stored reversed
// Need to reverse it back to normal
2021-10-14 09:08:24 +08:00
UByteArray hash ( ( const char * ) attrHeader + CpdExtModuleImageHashOffset , hashSize ) ;
2019-08-20 02:36:02 +08:00
std : : reverse ( hash . begin ( ) , hash . end ( ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-28 18:01:43 +08:00
info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh \n "
2019-08-20 02:36:02 +08:00
" Compression type: %Xh \n Uncompressed size: %Xh (%u) \n Compressed size: %Xh (%u) \n Global module ID: %Xh \n Image hash: " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) partition . size ( ) , ( UINT32 ) partition . size ( ) ,
2019-08-20 02:36:02 +08:00
attrHeader - > ExtensionType ,
attrHeader - > CompressionType ,
attrHeader - > UncompressedSize , attrHeader - > UncompressedSize ,
attrHeader - > CompressedSize , attrHeader - > CompressedSize ,
attrHeader - > GlobalModuleId ) + UString ( hash . toHex ( ) . constData ( ) ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// 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 ) ;
}
2022-08-28 18:47:01 +08:00
2022-08-29 14:23:38 +08:00
// There needs to be a more generic way to do it, but it is fine for now
2021-10-14 08:34:38 +08:00
if ( extHeader - > Type > CPD_EXT_TYPE_TBT_METADATA
& & extHeader - > Type ! = CPD_EXT_TYPE_GMF_CERTIFICATE
& & extHeader - > Type ! = CPD_EXT_TYPE_GMF_BODY
& & extHeader - > Type ! = CPD_EXT_TYPE_KEY_MANIFEST_EXT
& & extHeader - > Type ! = CPD_EXT_TYPE_SIGNED_PACKAGE_INFO_EXT
& & extHeader - > Type ! = CPD_EXT_TYPE_SPS_PLATFORM_ID ) {
2019-08-20 02:36:02 +08:00
msg ( usprintf ( " %s: CPD extention of unknown type found " , __FUNCTION__ ) , extIndex ) ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
offset + = extHeader - > Length ;
}
else break ;
// TODO: add padding at the end
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
return U_SUCCESS ;
}
USTATUS FfsParser : : parseSignedPackageInfoData ( const UModelIndex & index )
{
if ( ! index . isValid ( ) ) {
return U_INVALID_PARAMETER ;
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
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 ) ) {
2021-10-14 08:34:38 +08:00
// TODO: check sanity of moduleHeader->HashSize
2021-10-14 09:08:24 +08:00
UByteArray module ( ( const char * ) moduleHeader , CpdExtSignedPkgMetadataHashOffset + moduleHeader - > HashSize ) ;
2021-10-07 23:51:39 +08:00
UString name = usprintf ( " %.12s " , moduleHeader - > Name ) ;
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
// This hash is stored reversed
// Need to reverse it back to normal
2021-10-14 09:08:24 +08:00
UByteArray hash ( ( const char * ) moduleHeader + CpdExtSignedPkgMetadataHashOffset , moduleHeader - > HashSize ) ;
2019-08-20 02:36:02 +08:00
std : : reverse ( hash . begin ( ) , hash . end ( ) ) ;
2022-08-28 18:47:01 +08:00
2022-08-28 18:01:43 +08:00
UString info = usprintf ( " Full size: %Xh (%u) \n Type: %Xh \n Hash algorithm: %Xh \n Hash size: %Xh (%u) \n Metadata size: %Xh (%u) \n Metadata hash: " ,
2022-08-28 18:47:01 +08:00
( UINT32 ) module . size ( ) , ( UINT32 ) module . size ( ) ,
2019-08-20 02:36:02 +08:00
moduleHeader - > Type ,
moduleHeader - > HashAlgorithm ,
moduleHeader - > HashSize , moduleHeader - > HashSize ,
moduleHeader - > MetadataSize , moduleHeader - > MetadataSize ) + UString ( hash . toHex ( ) . constData ( ) ) ;
// Add tree otem
2022-08-25 04:17:51 +08:00
model - > addItem ( offset , Types : : CpdSpiEntry , 0 , name , UString ( ) , info , UByteArray ( ) , module , UByteArray ( ) , Fixed , index ) ;
2019-08-20 02:36:02 +08:00
offset + = module . size ( ) ;
}
else break ;
// TODO: add padding at the end
}
2022-08-28 18:47:01 +08:00
2019-08-20 02:36:02 +08:00
return U_SUCCESS ;
}
2021-10-07 23:51:39 +08:00
void FfsParser : : outputInfo ( void ) {
// Show ffsParser's messages
std : : vector < std : : pair < UString , UModelIndex > > messages = getMessages ( ) ;
for ( size_t i = 0 ; i < messages . size ( ) ; i + + ) {
std : : cout < < ( const char * ) messages [ i ] . first . toLocal8Bit ( ) < < std : : endl ;
}
2022-08-28 18:47:01 +08:00
2021-10-07 23:51:39 +08:00
// Get last VTF
std : : vector < std : : pair < std : : vector < UString > , UModelIndex > > fitTable = getFitTable ( ) ;
if ( fitTable . size ( ) ) {
std : : cout < < " --------------------------------------------------------------------------- " < < std : : endl ;
std : : cout < < " Address | Size | Ver | CS | Type / Info " < < std : : endl ;
std : : cout < < " --------------------------------------------------------------------------- " < < std : : endl ;
for ( size_t i = 0 ; i < fitTable . size ( ) ; i + + ) {
std : : cout
2022-08-28 18:47:01 +08:00
< < ( const char * ) fitTable [ i ] . first [ 0 ] . toLocal8Bit ( ) < < " | "
< < ( const char * ) fitTable [ i ] . first [ 1 ] . toLocal8Bit ( ) < < " | "
< < ( const char * ) fitTable [ i ] . first [ 2 ] . toLocal8Bit ( ) < < " | "
< < ( const char * ) fitTable [ i ] . first [ 3 ] . toLocal8Bit ( ) < < " | "
< < ( const char * ) fitTable [ i ] . first [ 4 ] . toLocal8Bit ( ) < < " | "
< < ( const char * ) fitTable [ i ] . first [ 5 ] . toLocal8Bit ( ) < < std : : endl ;
2021-10-07 23:51:39 +08:00
}
}
2022-08-28 18:47:01 +08:00
2021-10-07 23:51:39 +08:00
// Get security info
UString secInfo = getSecurityInfo ( ) ;
if ( ! secInfo . isEmpty ( ) ) {
2022-08-29 14:23:38 +08:00
std : : cout < < " --------------------------------------------------------------------------- " < < std : : endl ;
2021-10-07 23:51:39 +08:00
std : : cout < < " Security Info " < < std : : endl ;
2022-08-29 14:23:38 +08:00
std : : cout < < " --------------------------------------------------------------------------- " < < std : : endl ;
2021-10-07 23:51:39 +08:00
std : : cout < < ( const char * ) secInfo . toLocal8Bit ( ) < < std : : endl ;
}
}