]> git.proxmox.com Git - mirror_edk2.git/commitdiff
IntelFsp2Pkg: Support Config File and Binary delta comparison
authorLoo, Tung Lun <tung.lun.loo@intel.com>
Tue, 17 Aug 2021 07:43:12 +0000 (15:43 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 1 Sep 2021 12:40:26 +0000 (12:40 +0000)
BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3567

This patch is to enable config editor to have a new feature that
can spell out the delta between the default configuration files'
data, such as YAML and BSF, against the data stored in the binary.
This can help users understand and track the difference when
modifications are made.

Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Signed-off-by: Loo Tung Lun <tung.lun.loo@intel.com>
Reviewed-by: Chasel Chiu <chasel.chiu@intel.com>
IntelFsp2Pkg/Tools/ConfigEditor/ConfigEditor.py
IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py

index 008c7d7a160ad863037dde4955959a0b7b8c8009..680b90e09d8d31810ba491bb219fb307c39f34c1 100644 (file)
@@ -807,12 +807,12 @@ class application(tkinter.Frame):
         self.page_id = ''\r
         self.page_list = {}\r
         self.conf_list = {}\r
+        self.cfg_page_dict = {}\r
         self.cfg_data_obj = None\r
         self.org_cfg_data_bin = None\r
         self.in_left = state()\r
         self.in_right = state()\r
         self.search_text = ''\r
-        self.binseg_dict = {}\r
 \r
         # Check if current directory contains a file with a .yaml extension\r
         # if not default self.last_dir to a Platform directory where it is\r
@@ -1009,10 +1009,17 @@ class application(tkinter.Frame):
             return visible\r
         if self.cfg_data_obj.binseg_dict:\r
             str_split = item['path'].split('.')\r
-            if self.cfg_data_obj.binseg_dict[str_split[-2]] == -1:\r
-                visible = False\r
-                widget.grid_remove()\r
-                return visible\r
+            if str_split[-2] not in CGenYamlCfg.available_fv and \\r
+                    str_split[-2] not in CGenYamlCfg.missing_fv:\r
+                if self.cfg_data_obj.binseg_dict[str_split[-3]] == -1:\r
+                    visible = False\r
+                    widget.grid_remove()\r
+                    return visible\r
+            else:\r
+                if self.cfg_data_obj.binseg_dict[str_split[-2]] == -1:\r
+                    visible = False\r
+                    widget.grid_remove()\r
+                    return visible\r
         result = 1\r
         if item['condition']:\r
             result = self.evaluate_condition(item)\r
@@ -1371,8 +1378,34 @@ class application(tkinter.Frame):
         self.clear_widgets_inLayout()\r
         self.on_config_page_select_change(None)\r
 \r
+    def set_config_data_page(self):\r
+        page_id_list = []\r
+        for idx, page in enumerate(\r
+                self.cfg_data_obj._cfg_page['root']['child']):\r
+            page_id_list.append(list(page.keys())[0])\r
+            page_list = self.cfg_data_obj.get_cfg_list(page_id_list[idx])\r
+            self.cfg_page_dict[page_id_list[idx]] = 0\r
+            for item in page_list:\r
+                str_split = item['path'].split('.')\r
+                if str_split[-2] not in CGenYamlCfg.available_fv and \\r
+                        str_split[-2] not in CGenYamlCfg.missing_fv:\r
+                    if self.cfg_data_obj.binseg_dict[str_split[-3]] != -1:\r
+                        self.cfg_page_dict[page_id_list[idx]] += 1\r
+                else:\r
+                    if self.cfg_data_obj.binseg_dict[str_split[-2]] != -1:\r
+                        self.cfg_page_dict[page_id_list[idx]] += 1\r
+        removed_page = 0\r
+        for idx, id in enumerate(page_id_list):\r
+            if self.cfg_page_dict[id] == 0:\r
+                del self.cfg_data_obj._cfg_page['root']['child'][idx-removed_page]  # noqa: E501\r
+                removed_page += 1\r
+\r
     def reload_config_data_from_bin(self, bin_dat):\r
         self.cfg_data_obj.load_default_from_bin(bin_dat)\r
+        self.set_config_data_page()\r
+        self.left.delete(*self.left.get_children())\r
+        self.build_config_page_tree(self.cfg_data_obj.get_cfg_page()['root'],\r
+                                    '')\r
         self.refresh_config_data_page()\r
 \r
     def set_config_item_value(self, item, value_str):\r
index 611a9a9c726602fd0f338d919ea4407101953f55..b593885807df04242a2475256965192464d05230 100644 (file)
@@ -13,6 +13,7 @@ import string
 import operator as op\r
 import ast\r
 import tkinter.messagebox as messagebox\r
+import tkinter\r
 \r
 from datetime import date\r
 from collections import OrderedDict\r
@@ -583,7 +584,6 @@ class CGenYamlCfg:
         self._mode = ''\r
         self._debug = False\r
         self._macro_dict = {}\r
-        self.bin_offset = []\r
         self.binseg_dict = {}\r
         self.initialize()\r
 \r
@@ -1046,6 +1046,7 @@ option format '%s' !" % option)
                 try:\r
                     value = self.reformat_value_str(act_cfg['value'],\r
                                                     act_cfg['length'])\r
+\r
                 except Exception:\r
                     value = act_cfg['value']\r
             length = bit_len // 8\r
@@ -1298,18 +1299,85 @@ option format '%s' !" % option)
         self.traverse_cfg_tree(_get_field_value, top)\r
         return result\r
 \r
+    data_diff = ''\r
+\r
+    def find_data_difference(self, act_val, act_cfg):\r
+        # checks for any difference between BSF and Binary file\r
+        config_val = ''\r
+        if act_val != act_cfg['value']:\r
+\r
+            if 'DEC' in act_cfg['type']:\r
+                bsf_val = '0x%x' % int(act_val)\r
+                if bsf_val != act_cfg['value']:\r
+                    config_val = bsf_val\r
+                else:\r
+                    config_val = ''\r
+            else:\r
+                config_val = act_val\r
+\r
+            available_fv1 = 'none'\r
+            available_fv2 = 'none'\r
+\r
+            if self.detect_fsp():\r
+                if len(self.available_fv) >= 1:\r
+                    if len(self.available_fv) > 1:\r
+                        available_fv1 = self.available_fv[1]\r
+                        if self.available_fv[2]:\r
+                            available_fv2 = self.available_fv[2]\r
+            else:\r
+                available_fv1 = self.available_fv[1]\r
+                if act_cfg['length'] == 16:\r
+                    config_val = int(config_val, 16)\r
+                    config_val = '0x%x' % config_val\r
+                    act_cfg['value'] = int(\r
+                        act_cfg['value'], 16)\r
+                    act_cfg['value'] = '0x%x' %  \\r
+                        act_cfg['value']\r
+\r
+            if config_val:\r
+                string = ('.' + act_cfg['cname'])\r
+                if (act_cfg['path'].endswith(self.available_fv[0] + string)\r
+                    or act_cfg['path'].endswith(available_fv1 + string)\r
+                    or act_cfg['path'].endswith(available_fv2 + string)) \\r
+                    and 'BsfSkip' not in act_cfg['cname'] \\r
+                        and 'Reserved' not in act_cfg['name']:\r
+                    if act_cfg['option'] != '':\r
+                        if act_cfg['length'] == 8:\r
+                            config_val = int(config_val, 16)\r
+                            config_val = '0x%x' % config_val\r
+                            act_cfg['value'] = int(\r
+                                act_cfg['value'], 16)\r
+                            act_cfg['value'] = '0x%x' %  \\r
+                                act_cfg['value']\r
+                        option = act_cfg['option']\r
+\r
+                        cfg_val = ''\r
+                        bin_val = ''\r
+                        for i in option.split(','):\r
+                            if act_cfg['value'] in i:\r
+                                bin_val = i\r
+                            elif config_val in i:\r
+                                cfg_val = i\r
+                        if cfg_val != '' and bin_val != '':\r
+                            self.data_diff += '\n\nBinary:        ' \\r
+                                + act_cfg['name'] \\r
+                                + ': ' + bin_val.replace(' ', '') \\r
+                                + '\nConfig file:   ' \\r
+                                + act_cfg['name'] + ': ' \\r
+                                + cfg_val.replace(' ', '') + '\n'\r
+                    else:\r
+                        self.data_diff += '\n\nBinary:        ' \\r
+                            + act_cfg['name'] + ': ' + act_cfg['value'] \\r
+                            + '\nConfig file:   ' + act_cfg['name'] \\r
+                            + ': ' + config_val + '\n'\r
+\r
     def set_field_value(self, top, value_bytes, force=False):\r
         def _set_field_value(name, cfgs, level):\r
             if 'indx' not in cfgs:\r
                 return\r
             act_cfg = self.get_item_by_index(cfgs['indx'])\r
             actual_offset = act_cfg['offset'] - struct_info['offset']\r
-            set_value = True\r
-            for each in self.bin_offset:\r
-                if actual_offset in range(each[0], (each[0] + each[2]) * 8):\r
-                    if each[1] < 0:\r
-                        set_value = False\r
-            if set_value and force or act_cfg['value'] == '':\r
+            if force or act_cfg['value'] == '':\r
                 value = get_bits_from_bytes(full_bytes,\r
                                             actual_offset,\r
                                             act_cfg['length'])\r
@@ -1321,6 +1389,7 @@ option format '%s' !" % option)
                                                         act_val)\r
                 act_cfg['value'] = self.format_value_to_str(\r
                     value, act_cfg['length'], act_val)\r
+                self.find_data_difference(act_val, act_cfg)\r
 \r
         if 'indx' in top:\r
             # it is config option\r
@@ -1438,6 +1507,9 @@ for '%s' !" % (act_cfg['value'], act_cfg['path']))
 \r
         return bin_segs\r
 \r
+    available_fv = []\r
+    missing_fv = []\r
+\r
     def extract_cfg_from_bin(self, bin_data):\r
         # get cfg bin length\r
         cfg_bins = bytearray()\r
@@ -1445,12 +1517,12 @@ for '%s' !" % (act_cfg['value'], act_cfg['path']))
         Dummy_offset = 0\r
         for each in bin_segs:\r
             if each[1] != -1:\r
-                self.bin_offset.append([Dummy_offset, each[1], each[2]])\r
                 cfg_bins.extend(bin_data[each[1]:each[1] + each[2]])\r
+                self.available_fv.append(each[0])\r
             else:\r
+                self.missing_fv.append(each[0])\r
                 string = each[0] + ' is not availabe.'\r
                 messagebox.showinfo('', string)\r
-                self.bin_offset.append([Dummy_offset, each[1], each[2]])\r
                 cfg_bins.extend(bytearray(each[2]))\r
             Dummy_offset += each[2]\r
         return cfg_bins\r
@@ -1476,10 +1548,41 @@ for '%s' !" % (act_cfg['value'], act_cfg['path']))
         print('Patched the loaded binary successfully !')\r
         return bin_data\r
 \r
+    def show_data_difference(self, data_diff):\r
+        # Displays if any data difference detected in BSF and Binary file\r
+        pop_up_text = 'There are differences in Config file and binary '\\r
+            'data detected!\n'\r
+        pop_up_text += data_diff\r
+\r
+        window = tkinter.Tk()\r
+        window.title("Data Difference")\r
+        window.resizable(1, 1)\r
+        # Window Size\r
+        window.geometry("800x400")\r
+        frame = tkinter.Frame(window, height=800, width=700)\r
+        frame.pack(side=tkinter.BOTTOM)\r
+        # Vertical (y) Scroll Bar\r
+        scroll = tkinter.Scrollbar(window)\r
+        scroll.pack(side=tkinter.RIGHT, fill=tkinter.Y)\r
+\r
+        text = tkinter.Text(window, wrap=tkinter.NONE,\r
+                            yscrollcommand=scroll.set,\r
+                            width=700, height=400)\r
+        text.insert(tkinter.INSERT, pop_up_text)\r
+        text.pack()\r
+        # Configure the scrollbars\r
+        scroll.config(command=text.yview)\r
+        exit_button = tkinter.Button(\r
+            window, text="Close", command=window.destroy)\r
+        exit_button.pack(in_=frame, side=tkinter.RIGHT, padx=20, pady=10)\r
+\r
     def load_default_from_bin(self, bin_data):\r
         self._old_bin = bin_data\r
         cfg_bins = self.extract_cfg_from_bin(bin_data)\r
         self.set_field_value(self._cfg_tree, cfg_bins, True)\r
+\r
+        if self.data_diff:\r
+            self.show_data_difference(self.data_diff)\r
         return cfg_bins\r
 \r
     def generate_binary_array(self, path=''):\r