1212import string
1313import operator as op
1414import ast
15+ import tkinter .messagebox as messagebox
16+ import tkinter
1517
1618from datetime import date
1719from collections import OrderedDict
1820from CommonUtility import value_to_bytearray , value_to_bytes , \
1921 bytes_to_value , get_bits_from_bytes , set_bits_to_bytes
2022
23+ # FFS file structure constants
24+ FFS_GUID_SIZE = 16
25+ FFS_HEADER_SIZE = 24
26+ FFS_SEARCH_RANGE = 4096 # Search within 4KB after GUID
27+
28+ import uuid
29+ import struct
30+
31+ # FSP UPD FFS GUID definitions
32+ FSP_T_UPD_FFS_GUID = uuid .UUID ('70BCF6A5-FFB1-47D8-B1AE-EFE5508E23EA' )
33+ FSP_M_UPD_FFS_GUID = uuid .UUID ('D5B86AEA-6AF7-40D4-8014-982301BC3D89' )
34+ FSP_S_UPD_FFS_GUID = uuid .UUID ('E3CD9B18-998C-4F76-B65E-98B154E5446F' )
35+
36+ # UPD signature to GUID mapping
37+ def get_upd_guid (upd_signature ):
38+ """Get FFS GUID for a given UPD signature based on suffix"""
39+ if upd_signature .endswith ('UPD_T' ):
40+ return FSP_T_UPD_FFS_GUID
41+ elif upd_signature .endswith ('UPD_M' ):
42+ return FSP_M_UPD_FFS_GUID
43+ elif upd_signature .endswith ('UPD_S' ):
44+ return FSP_S_UPD_FFS_GUID
45+ return None
46+
47+
48+ def guid_to_bytes (guid ):
49+ """Convert UUID to bytes in EFI GUID format (mixed endian)"""
50+ # EFI GUID format: first 3 fields are little-endian, last 2 are big-endian
51+ guid_struct = struct .pack ('<IHH' , guid .time_low , guid .time_mid , guid .time_hi_version )
52+ guid_struct += struct .pack ('>H' , guid .clock_seq_hi_variant << 8 | guid .clock_seq_low )
53+ guid_struct += guid .node .to_bytes (6 , 'big' )
54+ return guid_struct
55+
56+
57+ def bytes_to_guid (data ):
58+ """Convert 16 bytes in EFI GUID format to UUID"""
59+ if len (data ) < FFS_GUID_SIZE :
60+ return None
61+ time_low = struct .unpack ('<I' , data [0 :4 ])[0 ]
62+ time_mid = struct .unpack ('<H' , data [4 :6 ])[0 ]
63+ time_hi_version = struct .unpack ('<H' , data [6 :8 ])[0 ]
64+ clock_seq = struct .unpack ('>H' , data [8 :10 ])[0 ]
65+ node = int .from_bytes (data [10 :16 ], 'big' )
66+
67+ return uuid .UUID (fields = (time_low , time_mid , time_hi_version ,
68+ clock_seq >> 8 , clock_seq & 0xFF , node ))
69+
70+
2171# Generated file copyright header
2272__copyright_tmp__ = """/** @file
2373
@@ -637,7 +687,6 @@ def __init__(self):
637687 self ._macro_dict = {}
638688 self .binseg_dict = {}
639689 self .initialize ()
640- self ._tk = self .import_tkinter ()
641690
642691 def initialize (self ):
643692 self ._old_bin = None
@@ -1639,14 +1688,45 @@ def _get_cfg_segment(name, cfgs, level):
16391688
16401689 return cfg_segs
16411690
1642- def import_tkinter (self ):
1643- try :
1644- import tkinter
1645- import tkinter .messagebox
1646- return tkinter
1647- except ImportError :
1648- print ('tkinter is not supported under current OS' )
1649- return None
1691+ def find_upd_in_ffs_by_guid (self , bin_data , upd_signature , ffs_guid ):
1692+ """
1693+ Find UPD signature within a specific FFS file identified by GUID.
1694+
1695+ Args:
1696+ bin_data: Binary data to search in
1697+ upd_signature: UPD signature string (e.g., 'XXXUPD_M')
1698+ ffs_guid: UUID of the FFS file to search in
1699+
1700+ Returns:
1701+ Position of UPD signature if found, -1 otherwise
1702+ """
1703+ if not ffs_guid :
1704+ return - 1
1705+
1706+ # Convert GUID to bytes for searching
1707+ guid_bytes = guid_to_bytes (ffs_guid )
1708+ sig_bytes = upd_signature .encode ()
1709+
1710+ # Search for all occurrences of the GUID
1711+ search_pos = 0
1712+ while True :
1713+ guid_pos = bin_data .find (guid_bytes , search_pos )
1714+ if guid_pos < 0 :
1715+ break
1716+
1717+ # Search for UPD signature within FFS_SEARCH_RANGE after GUID
1718+ search_start = guid_pos
1719+ search_end = min (guid_pos + FFS_SEARCH_RANGE , len (bin_data ))
1720+
1721+ sig_pos = bin_data .find (sig_bytes , search_start , search_end )
1722+ if sig_pos >= 0 :
1723+ print (f"Found { upd_signature } at offset 0x{ sig_pos :X} within FFS GUID { ffs_guid } " )
1724+ return sig_pos
1725+
1726+ # Continue searching for next occurrence of this GUID
1727+ search_pos = guid_pos + FFS_GUID_SIZE
1728+
1729+ return - 1
16501730
16511731 def get_bin_segment (self , bin_data ):
16521732 cfg_segs = self .get_cfg_segment ()
@@ -1656,25 +1736,36 @@ def get_bin_segment(self, bin_data):
16561736 if key == 0 :
16571737 bin_segs .append ([seg [0 ], 0 , len (bin_data )])
16581738 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 )
1669- if self ._tk :
1670- self ._tk .messagebox .showwarning ('Warning: ' , string )
1739+
1740+ pos = - 1
1741+
1742+ # Check if this UPD signature has a corresponding FFS GUID
1743+ ffs_guid = get_upd_guid (seg [0 ])
1744+ if ffs_guid :
1745+ pos = self .find_upd_in_ffs_by_guid (bin_data , seg [0 ], ffs_guid )
1746+ if pos >= 0 :
1747+ print (f"Using GUID-based search: found { seg [0 ]} at 0x{ pos :X} " )
1748+
1749+ # Fallback to original search if GUID-based search fails
1750+ if pos < 0 :
1751+ pos = bin_data .find (key )
1752+ if pos >= 0 :
1753+ # Check for multiple matches
1754+ next_pos = bin_data .find (key , pos + len (seg [0 ]))
1755+ if next_pos >= 0 :
1756+ if key == b'$SKLFSP$' or key == b'$BSWFSP$' :
1757+ string = ('Warning: Multiple matches for %s in '
1758+ 'binary!\n \n A workaround applied to such '
1759+ 'FSP 1.x binary to use second'
1760+ ' match instead of first match!' % key )
1761+ messagebox .showwarning ('Warning!' , string )
1762+ pos = next_pos
16711763 else :
1672- print ('Warning: ' , string )
1673- pos = next_pos
1674- else :
1675- print ("Warning: Multiple matches for '%s' "
1676- "in binary, the 1st instance will be used !"
1677- % seg [0 ])
1764+ print ("Warning: Multiple matches for '%s' "
1765+ "in binary, the 1st instance will be used !"
1766+ % seg [0 ])
1767+
1768+ if pos >= 0 :
16781769 bin_segs .append ([seg [0 ], pos , seg [2 ]])
16791770 self .binseg_dict [seg [0 ]] = pos
16801771 else :
@@ -1699,10 +1790,7 @@ def extract_cfg_from_bin(self, bin_data):
16991790 else :
17001791 self .missing_fv .append (each [0 ])
17011792 string = each [0 ] + ' is not availabe.'
1702- if self ._tk :
1703- self ._tk .messagebox .showinfo ('' , string )
1704- else :
1705- print ('warning: ' , string )
1793+ messagebox .showinfo ('' , string )
17061794 cfg_bins .extend (bytearray (each [2 ]))
17071795 Dummy_offset += each [2 ]
17081796 return cfg_bins
@@ -1729,34 +1817,32 @@ def save_current_to_bin(self):
17291817 return bin_data
17301818
17311819 def show_data_difference (self , data_diff ):
1732- if self ._tk is None :
1733- return
17341820 # Displays if any data difference detected in BSF and Binary file
17351821 pop_up_text = 'There are differences in Config file and binary ' \
17361822 'data detected!\n '
17371823 pop_up_text += data_diff
17381824
1739- window = self . _tk .Tk ()
1825+ window = tkinter .Tk ()
17401826 window .title ("Data Difference" )
17411827 window .resizable (1 , 1 )
17421828 # Window Size
17431829 window .geometry ("800x400" )
1744- frame = self . _tk .Frame (window , height = 800 , width = 700 )
1745- frame .pack (side = self . _tk .BOTTOM )
1830+ frame = tkinter .Frame (window , height = 800 , width = 700 )
1831+ frame .pack (side = tkinter .BOTTOM )
17461832 # Vertical (y) Scroll Bar
1747- scroll = self . _tk .Scrollbar (window )
1748- scroll .pack (side = self . _tk . RIGHT , fill = self . _tk .Y )
1833+ scroll = tkinter .Scrollbar (window )
1834+ scroll .pack (side = tkinter . RIGHT , fill = tkinter .Y )
17491835
1750- text = self . _tk . Text (window , wrap = self . _tk .NONE ,
1836+ text = tkinter . Text (window , wrap = tkinter .NONE ,
17511837 yscrollcommand = scroll .set ,
17521838 width = 700 , height = 400 )
1753- text .insert (self . _tk .INSERT , pop_up_text )
1839+ text .insert (tkinter .INSERT , pop_up_text )
17541840 text .pack ()
17551841 # Configure the scrollbars
17561842 scroll .config (command = text .yview )
1757- exit_button = self . _tk .Button (
1843+ exit_button = tkinter .Button (
17581844 window , text = "Close" , command = window .destroy )
1759- exit_button .pack (in_ = frame , side = self . _tk .RIGHT , padx = 20 , pady = 10 )
1845+ exit_button .pack (in_ = frame , side = tkinter .RIGHT , padx = 20 , pady = 10 )
17601846
17611847 def load_default_from_bin (self , bin_data ):
17621848 self ._old_bin = bin_data
0 commit comments