Skip to content

Commit 86920f4

Browse files
committed
IntelFsp2Pkg/Tools/ConfigEditor: Fixed data difference issue
Problem Description: load_default_from_bin caused data difference errors when loading fsp.bsf and fsp.fd, due to multiple identical UPD signatures. The original string search picked the first match, which could be the wrong region. Solution Implementation: Updated GenYamlCfg.py to locate UPD data by FFS GUID (FSP_T/M/S_UPD_FFS_GUID) before searching UPD signatures. This ensures correct region matching and retains the old string search as a fallback. Signed-off-by: Hsu JasonX <[email protected]>
1 parent 1c74842 commit 86920f4

File tree

1 file changed

+128
-42
lines changed

1 file changed

+128
-42
lines changed

IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py

Lines changed: 128 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,62 @@
1212
import string
1313
import operator as op
1414
import ast
15+
import tkinter.messagebox as messagebox
16+
import tkinter
1517

1618
from datetime import date
1719
from collections import OrderedDict
1820
from 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\nA 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\nA 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

Comments
 (0)