1818from CommonUtility import value_to_bytearray , value_to_bytes , \
1919 bytes_to_value , get_bits_from_bytes , set_bits_to_bytes
2020
21+ # FFS file structure constants
22+ FFS_GUID_SIZE = 16
23+ FFS_HEADER_SIZE = 24
24+ FFS_SEARCH_RANGE = 4096 # Search within 4KB after GUID
25+
26+ # FSP UPD FFS GUID definitions
27+ FSP_T_UPD_FFS_GUID = '70BCF6A5-FFB1-47D8-B1AE-EFE5508E23EA'
28+ FSP_M_UPD_FFS_GUID = 'D5B86AEA-6AF7-40D4-8014-982301BC3D89'
29+ FSP_S_UPD_FFS_GUID = 'E3CD9B18-998C-4F76-B65E-98B154E5446F'
30+
31+ def guid_str_to_bytes (guid_str ):
32+ """Convert GUID string to bytes in EFI GUID format (mixed endian)"""
33+ # Remove dashes and convert to bytes
34+ guid_str = guid_str .replace ('-' , '' )
35+
36+ # EFI GUID format: first 3 fields are little-endian, last 2 are big-endian
37+ # Parse: DWORD-WORD-WORD-BYTE[2]-BYTE[6]
38+ data1 = bytes .fromhex (guid_str [0 :8 ])[::- 1 ] # DWORD (4 bytes) - little endian
39+ data2 = bytes .fromhex (guid_str [8 :12 ])[::- 1 ] # WORD (2 bytes) - little endian
40+ data3 = bytes .fromhex (guid_str [12 :16 ])[::- 1 ] # WORD (2 bytes) - little endian
41+ data4 = bytes .fromhex (guid_str [16 :20 ]) # BYTE[2] (2 bytes) - big endian
42+ data5 = bytes .fromhex (guid_str [20 :32 ]) # BYTE[6] (6 bytes) - big endian
43+
44+ return data1 + data2 + data3 + data4 + data5
45+
46+ # UPD signature to GUID mapping
47+ def get_upd_guid (upd_signature ):
48+ """Get FFS GUID for a given UPD signature based on suffix"""
49+ if upd_signature .endswith ('UPD_T' ):
50+ return FSP_T_UPD_FFS_GUID
51+ elif upd_signature .endswith ('UPD_M' ):
52+ return FSP_M_UPD_FFS_GUID
53+ elif upd_signature .endswith ('UPD_S' ):
54+ return FSP_S_UPD_FFS_GUID
55+ return None
56+
2157# Generated file copyright header
2258__copyright_tmp__ = """/** @file
2359
@@ -1639,6 +1675,46 @@ def _get_cfg_segment(name, cfgs, level):
16391675
16401676 return cfg_segs
16411677
1678+ def find_upd_in_ffs_by_guid (self , bin_data , upd_signature , ffs_guid ):
1679+ """
1680+ Find UPD signature within a specific FFS file identified by GUID.
1681+
1682+ Args:
1683+ bin_data: Binary data to search in
1684+ upd_signature: UPD signature string (e.g., 'XXXUPD_M')
1685+ ffs_guid: GUID string of the FFS file to search in
1686+
1687+ Returns:
1688+ Position of UPD signature if found, -1 otherwise
1689+ """
1690+ if not ffs_guid :
1691+ return - 1
1692+
1693+ # Convert GUID string to bytes for searching
1694+ guid_bytes = guid_str_to_bytes (ffs_guid )
1695+ sig_bytes = upd_signature .encode ()
1696+
1697+ # Search for all occurrences of the GUID
1698+ search_pos = 0
1699+ while True :
1700+ guid_pos = bin_data .find (guid_bytes , search_pos )
1701+ if guid_pos < 0 :
1702+ break
1703+
1704+ # Search for UPD signature within FFS_SEARCH_RANGE after GUID
1705+ search_start = guid_pos
1706+ search_end = min (guid_pos + FFS_SEARCH_RANGE , len (bin_data ))
1707+
1708+ sig_pos = bin_data .find (sig_bytes , search_start , search_end )
1709+ if sig_pos >= 0 :
1710+ print (f"Found { upd_signature } at offset 0x{ sig_pos :X} within FFS GUID { ffs_guid } " )
1711+ return sig_pos
1712+
1713+ # Continue searching for next occurrence of this GUID
1714+ search_pos = guid_pos + FFS_GUID_SIZE
1715+
1716+ return - 1
1717+
16421718 def import_tkinter (self ):
16431719 try :
16441720 import tkinter
@@ -1656,16 +1732,28 @@ def get_bin_segment(self, bin_data):
16561732 if key == 0 :
16571733 bin_segs .append ([seg [0 ], 0 , len (bin_data )])
16581734 break
1659- pos = bin_data .find (key )
1660- if pos >= 0 :
1661- # ensure no other match for the key
1662- next_pos = bin_data .find (key , pos + len (seg [0 ]))
1663- if next_pos >= 0 :
1664- if key == b'$SKLFSP$' or key == b'$BSWFSP$' :
1665- string = ('Multiple matches for %s in '
1666- 'binary!\n \n A workaround applied to such '
1667- 'FSP 1.x binary to use second'
1668- ' match instead of first match!' % key )
1735+
1736+ pos = - 1
1737+
1738+ # Check if this UPD signature has a corresponding FFS GUID
1739+ ffs_guid = get_upd_guid (seg [0 ])
1740+ if ffs_guid :
1741+ pos = self .find_upd_in_ffs_by_guid (bin_data , seg [0 ], ffs_guid )
1742+ if pos >= 0 :
1743+ print (f"Using GUID-based search: found { seg [0 ]} at 0x{ pos :X} " )
1744+
1745+ # Fallback to original search if GUID-based search fails
1746+ if pos < 0 :
1747+ pos = bin_data .find (key )
1748+ if pos >= 0 :
1749+ # Check for multiple matches
1750+ next_pos = bin_data .find (key , pos + len (seg [0 ]))
1751+ if next_pos >= 0 :
1752+ if key == b'$SKLFSP$' or key == b'$BSWFSP$' :
1753+ string = ('Warning: Multiple matches for %s in '
1754+ 'binary!\n \n A workaround applied to such '
1755+ 'FSP 1.x binary to use second'
1756+ ' match instead of first match!' % key )
16691757 if self ._tk :
16701758 self ._tk .messagebox .showwarning ('Warning: ' , string )
16711759 else :
@@ -1675,12 +1763,13 @@ def get_bin_segment(self, bin_data):
16751763 print ("Warning: Multiple matches for '%s' "
16761764 "in binary, the 1st instance will be used !"
16771765 % seg [0 ])
1766+
1767+ if pos >= 0 :
16781768 bin_segs .append ([seg [0 ], pos , seg [2 ]])
16791769 self .binseg_dict [seg [0 ]] = pos
16801770 else :
16811771 bin_segs .append ([seg [0 ], - 1 , seg [2 ]])
16821772 self .binseg_dict [seg [0 ]] = - 1
1683- continue
16841773
16851774 return bin_segs
16861775
0 commit comments