summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py')
-rwxr-xr-xsrc/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py884
1 files changed, 884 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py b/src/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py
new file mode 100755
index 00000000..b3f2a3e5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py
@@ -0,0 +1,884 @@
+#!/usr/bin/env python
+## @ FspDscBsf2Yaml.py
+# This script convert DSC or BSF format file into YAML format
+#
+# Copyright(c) 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+import os
+import re
+import sys
+from datetime import date
+from collections import OrderedDict
+from functools import reduce
+
+from GenCfgOpt import CGenCfgOpt
+
+__copyright_tmp__ = """## @file
+#
+# YAML CFGDATA %s File.
+#
+# Copyright(c) %4d, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+"""
+
+__copyright_dsc__ = """## @file
+#
+# Copyright (c) %04d, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[PcdsDynamicVpd.Upd]
+ #
+ # Global definitions in BSF
+ # !BSF BLOCK:{NAME:"FSP UPD Configuration", VER:"0.1"}
+ #
+
+"""
+
+
+def Bytes2Val(Bytes):
+ return reduce(lambda x, y: (x << 8) | y, Bytes[::-1])
+
+
+def Str2Bytes(Value, Blen):
+ Result = bytearray(Value[1:-1], 'utf-8') # Excluding quotes
+ if len(Result) < Blen:
+ Result.extend(b'\x00' * (Blen - len(Result)))
+ return Result
+
+
+class CFspBsf2Dsc:
+
+ def __init__(self, bsf_file):
+ self.cfg_list = CFspBsf2Dsc.parse_bsf(bsf_file)
+
+ def get_dsc_lines(self):
+ return CFspBsf2Dsc.generate_dsc(self.cfg_list)
+
+ def save_dsc(self, dsc_file):
+ return CFspBsf2Dsc.generate_dsc(self.cfg_list, dsc_file)
+
+ @staticmethod
+ def parse_bsf(bsf_file):
+
+ fd = open(bsf_file, 'r')
+ bsf_txt = fd.read()
+ fd.close()
+
+ find_list = []
+ regex = re.compile(r'\s+Find\s+"(.*?)"(.*?)^\s+\$(.*?)\s+', re.S | re.MULTILINE)
+ for match in regex.finditer(bsf_txt):
+ find = match.group(1)
+ name = match.group(3)
+ if not name.endswith('_Revision'):
+ raise Exception("Unexpected CFG item following 'Find' !")
+ find_list.append((name, find))
+
+ idx = 0
+ count = 0
+ prefix = ''
+ chk_dict = {}
+ cfg_list = []
+ cfg_temp = {'find': '', 'cname': '', 'length': 0, 'value': '0', 'type': 'Reserved',
+ 'embed': '', 'page': '', 'option': '', 'instance': 0}
+ regex = re.compile(r'^\s+(\$(.*?)|Skip)\s+(\d+)\s+bytes(\s+\$_DEFAULT_\s+=\s+(.+?))?$',
+ re.S | re.MULTILINE)
+
+ for match in regex.finditer(bsf_txt):
+ dlen = int(match.group(3))
+ if match.group(1) == 'Skip':
+ key = 'gPlatformFspPkgTokenSpaceGuid_BsfSkip%d' % idx
+ val = ', '.join(['%02X' % ord(i) for i in '\x00' * dlen])
+ idx += 1
+ option = '$SKIP'
+ else:
+ key = match.group(2)
+ val = match.group(5)
+ option = ''
+
+ cfg_item = dict(cfg_temp)
+ finds = [i for i in find_list if i[0] == key]
+ if len(finds) > 0:
+ if count >= 1:
+ # Append a dummy one
+ cfg_item['cname'] = 'Dummy'
+ cfg_list.append(dict(cfg_item))
+ cfg_list[-1]['embed'] = '%s:TAG_%03X:END' % (prefix, ord(prefix[-1]))
+ prefix = finds[0][1]
+ cfg_item['embed'] = '%s:TAG_%03X:START' % (prefix, ord(prefix[-1]))
+ cfg_item['find'] = prefix
+ cfg_item['cname'] = 'Signature'
+ cfg_item['length'] = len(finds[0][1])
+ str2byte = Str2Bytes("'" + finds[0][1] + "'", len(finds[0][1]))
+ cfg_item['value'] = '0x%X' % Bytes2Val(str2byte)
+ cfg_list.append(dict(cfg_item))
+ cfg_item = dict(cfg_temp)
+ find_list.pop(0)
+ count = 0
+
+ cfg_item['cname'] = key
+ cfg_item['length'] = dlen
+ cfg_item['value'] = val
+ cfg_item['option'] = option
+
+ if key not in chk_dict.keys():
+ chk_dict[key] = 0
+ else:
+ chk_dict[key] += 1
+ cfg_item['instance'] = chk_dict[key]
+
+ cfg_list.append(cfg_item)
+ count += 1
+
+ if prefix:
+ cfg_item = dict(cfg_temp)
+ cfg_item['cname'] = 'Dummy'
+ cfg_item['embed'] = '%s:%03X:END' % (prefix, ord(prefix[-1]))
+ cfg_list.append(cfg_item)
+
+ option_dict = {}
+ selreg = re.compile(r'\s+Selection\s*(.+?)\s*,\s*"(.*?)"$', re.S | re.MULTILINE)
+ regex = re.compile(r'^List\s&(.+?)$(.+?)^EndList$', re.S | re.MULTILINE)
+ for match in regex.finditer(bsf_txt):
+ key = match.group(1)
+ option_dict[key] = []
+ for select in selreg.finditer(match.group(2)):
+ option_dict[key].append((int(select.group(1), 0), select.group(2)))
+
+ chk_dict = {}
+ pagereg = re.compile(r'^Page\s"(.*?)"$(.+?)^EndPage$', re.S | re.MULTILINE)
+ for match in pagereg.finditer(bsf_txt):
+ page = match.group(1)
+ for line in match.group(2).splitlines():
+ match = re.match(r'\s+(Combo|EditNum)\s\$(.+?),\s"(.*?)",\s(.+?),$', line)
+ if match:
+ cname = match.group(2)
+ if cname not in chk_dict.keys():
+ chk_dict[cname] = 0
+ else:
+ chk_dict[cname] += 1
+ instance = chk_dict[cname]
+ cfg_idxs = [i for i, j in enumerate(cfg_list) if j['cname'] == cname and j['instance'] == instance]
+ if len(cfg_idxs) != 1:
+ raise Exception("Multiple CFG item '%s' found !" % cname)
+ cfg_item = cfg_list[cfg_idxs[0]]
+ cfg_item['page'] = page
+ cfg_item['type'] = match.group(1)
+ cfg_item['prompt'] = match.group(3)
+ cfg_item['range'] = None
+ if cfg_item['type'] == 'Combo':
+ cfg_item['option'] = option_dict[match.group(4)[1:]]
+ elif cfg_item['type'] == 'EditNum':
+ cfg_item['option'] = match.group(4)
+ match = re.match(r'\s+ Help\s"(.*?)"$', line)
+ if match:
+ cfg_item['help'] = match.group(1)
+
+ match = re.match(r'\s+"Valid\srange:\s(.*)"$', line)
+ if match:
+ parts = match.group(1).split()
+ cfg_item['option'] = (
+ (int(parts[0], 0), int(parts[2], 0), cfg_item['option']))
+
+ return cfg_list
+
+ @staticmethod
+ def generate_dsc(option_list, dsc_file=None):
+ dsc_lines = []
+ header = '%s' % (__copyright_dsc__ % date.today().year)
+ dsc_lines.extend(header.splitlines())
+
+ pages = []
+ for cfg_item in option_list:
+ if cfg_item['page'] and (cfg_item['page'] not in pages):
+ pages.append(cfg_item['page'])
+
+ page_id = 0
+ for page in pages:
+ dsc_lines.append(' # !BSF PAGES:{PG%02X::"%s"}' % (page_id, page))
+ page_id += 1
+ dsc_lines.append('')
+
+ last_page = ''
+ for option in option_list:
+ dsc_lines.append('')
+ default = option['value']
+ pos = option['cname'].find('_')
+ name = option['cname'][pos + 1:]
+
+ if option['find']:
+ dsc_lines.append(' # !BSF FIND:{%s}' % option['find'])
+ dsc_lines.append('')
+
+ if option['instance'] > 0:
+ name = name + '_%s' % option['instance']
+
+ if option['embed']:
+ dsc_lines.append(' # !HDR EMBED:{%s}' % option['embed'])
+
+ if option['type'] == 'Reserved':
+ dsc_lines.append(' # !BSF NAME:{Reserved} TYPE:{Reserved}')
+ if option['option'] == '$SKIP':
+ dsc_lines.append(' # !BSF OPTION:{$SKIP}')
+ else:
+ prompt = option['prompt']
+
+ if last_page != option['page']:
+ last_page = option['page']
+ dsc_lines.append(' # !BSF PAGE:{PG%02X}' % (pages.index(option['page'])))
+
+ if option['type'] == 'Combo':
+ dsc_lines.append(' # !BSF NAME:{%s} TYPE:{%s}' %
+ (prompt, option['type']))
+ ops = []
+ for val, text in option['option']:
+ ops.append('0x%x:%s' % (val, text))
+ dsc_lines.append(' # !BSF OPTION:{%s}' % (', '.join(ops)))
+ elif option['type'] == 'EditNum':
+ cfg_len = option['length']
+ if ',' in default and cfg_len > 8:
+ dsc_lines.append(' # !BSF NAME:{%s} TYPE:{Table}' % (prompt))
+ if cfg_len > 16:
+ cfg_len = 16
+ ops = []
+ for i in range(cfg_len):
+ ops.append('%X:1:HEX' % i)
+ dsc_lines.append(' # !BSF OPTION:{%s}' % (', '.join(ops)))
+ else:
+ dsc_lines.append(
+ ' # !BSF NAME:{%s} TYPE:{%s, %s,(0x%X, 0x%X)}' %
+ (prompt, option['type'], option['option'][2],
+ option['option'][0], option['option'][1]))
+ dsc_lines.append(' # !BSF HELP:{%s}' % option['help'])
+
+ if ',' in default:
+ default = '{%s}' % default
+ dsc_lines.append(' gCfgData.%-30s | * | 0x%04X | %s' %
+ (name, option['length'], default))
+
+ if dsc_file:
+ fd = open(dsc_file, 'w')
+ fd.write('\n'.join(dsc_lines))
+ fd.close()
+
+ return dsc_lines
+
+
+class CFspDsc2Yaml():
+
+ def __init__(self):
+ self._Hdr_key_list = ['EMBED', 'STRUCT']
+ self._Bsf_key_list = ['NAME', 'HELP', 'TYPE', 'PAGE', 'PAGES', 'OPTION',
+ 'CONDITION', 'ORDER', 'MARKER', 'SUBT', 'FIELD', 'FIND']
+ self.gen_cfg_data = None
+ self.cfg_reg_exp = re.compile(r"^([_a-zA-Z0-9$\(\)]+)\s*\|\s*(0x[0-9A-F]+|\*)\s*\|"
+ + r"\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)")
+ self.bsf_reg_exp = re.compile(r"(%s):{(.+?)}(?:$|\s+)" % '|'.join(self._Bsf_key_list))
+ self.hdr_reg_exp = re.compile(r"(%s):{(.+?)}" % '|'.join(self._Hdr_key_list))
+ self.prefix = ''
+ self.unused_idx = 0
+ self.offset = 0
+ self.base_offset = 0
+
+ def load_config_data_from_dsc(self, file_name):
+ """
+ Load and parse a DSC CFGDATA file.
+ """
+ gen_cfg_data = CGenCfgOpt('FSP')
+ if file_name.endswith('.dsc'):
+ # if gen_cfg_data.ParseDscFileYaml(file_name, '') != 0:
+ if gen_cfg_data.ParseDscFile(file_name, '') != 0:
+ raise Exception('DSC file parsing error !')
+ if gen_cfg_data.CreateVarDict() != 0:
+ raise Exception('DSC variable creation error !')
+ else:
+ raise Exception('Unsupported file "%s" !' % file_name)
+ self.gen_cfg_data = gen_cfg_data
+
+ def print_dsc_line(self):
+ """
+ Debug function to print all DSC lines.
+ """
+ for line in self.gen_cfg_data._DscLines:
+ print(line)
+
+ def format_value(self, field, text, indent=''):
+ """
+ Format a CFGDATA item into YAML format.
+ """
+ if(not text.startswith('!expand')) and (': ' in text):
+ tgt = ':' if field == 'option' else '- '
+ text = text.replace(': ', tgt)
+ lines = text.splitlines()
+ if len(lines) == 1 and field != 'help':
+ return text
+ else:
+ return '>\n ' + '\n '.join([indent + i.lstrip() for i in lines])
+
+ def reformat_pages(self, val):
+ # Convert XXX:YYY into XXX::YYY format for page definition
+ parts = val.split(',')
+ if len(parts) <= 1:
+ return val
+
+ new_val = []
+ for each in parts:
+ nodes = each.split(':')
+ if len(nodes) == 2:
+ each = '%s::%s' % (nodes[0], nodes[1])
+ new_val.append(each)
+ ret = ','.join(new_val)
+ return ret
+
+ def reformat_struct_value(self, utype, val):
+ # Convert DSC UINT16/32/64 array into new format by
+ # adding prefix 0:0[WDQ] to provide hint to the array format
+ if utype in ['UINT16', 'UINT32', 'UINT64']:
+ if val and val[0] == '{' and val[-1] == '}':
+ if utype == 'UINT16':
+ unit = 'W'
+ elif utype == 'UINT32':
+ unit = 'D'
+ else:
+ unit = 'Q'
+ val = '{ 0:0%s, %s }' % (unit, val[1:-1])
+ return val
+
+ def process_config(self, cfg):
+ if 'page' in cfg:
+ cfg['page'] = self.reformat_pages(cfg['page'])
+
+ if 'struct' in cfg:
+ cfg['value'] = self.reformat_struct_value(cfg['struct'], cfg['value'])
+
+ def parse_dsc_line(self, dsc_line, config_dict, init_dict, include):
+ """
+ Parse a line in DSC and update the config dictionary accordingly.
+ """
+ init_dict.clear()
+ match = re.match(r'g(CfgData|\w+FspPkgTokenSpaceGuid)\.(.+)', dsc_line)
+ if match:
+ match = self.cfg_reg_exp.match(match.group(2))
+ if not match:
+ return False
+ config_dict['cname'] = self.prefix + match.group(1)
+ value = match.group(4).strip()
+ length = match.group(3).strip()
+ config_dict['length'] = length
+ config_dict['value'] = value
+ if match.group(2) == '*':
+ self.offset += int(length, 0)
+ else:
+ org_offset = int(match.group(2), 0)
+ if org_offset == 0:
+ self.base_offset = self.offset
+ offset = org_offset + self.base_offset
+ if self.offset != offset:
+ if offset > self.offset:
+ init_dict['padding'] = offset - self.offset
+ self.offset = offset + int(length, 0)
+ return True
+
+ match = re.match(r"^\s*#\s+!([<>])\s+include\s+(.+)", dsc_line)
+ if match and len(config_dict) == 0:
+ # !include should not be inside a config field
+ # if so, do not convert include into YAML
+ init_dict = dict(config_dict)
+ config_dict.clear()
+ config_dict['cname'] = '$ACTION'
+ if match.group(1) == '<':
+ config_dict['include'] = match.group(2)
+ else:
+ config_dict['include'] = ''
+ return True
+
+ match = re.match(r"^\s*#\s+(!BSF|!HDR)\s+(.+)", dsc_line)
+ if not match:
+ return False
+
+ remaining = match.group(2)
+ if match.group(1) == '!BSF':
+ result = self.bsf_reg_exp.findall(remaining)
+ if not result:
+ return False
+
+ for each in result:
+ key = each[0].lower()
+ val = each[1]
+ if key == 'field':
+ name = each[1]
+ if ':' not in name:
+ raise Exception('Incorrect bit field format !')
+ parts = name.split(':')
+ config_dict['length'] = parts[1]
+ config_dict['cname'] = '@' + parts[0]
+ return True
+ elif key in ['pages', 'page', 'find']:
+ init_dict = dict(config_dict)
+ config_dict.clear()
+ config_dict['cname'] = '$ACTION'
+ if key == 'find':
+ config_dict['find'] = val
+ else:
+ config_dict['page'] = val
+ return True
+ elif key == 'subt':
+ config_dict.clear()
+ parts = each[1].split(':')
+ tmp_name = parts[0][:-5]
+ if tmp_name == 'CFGHDR':
+ cfg_tag = '_$FFF_'
+ sval = '!expand { %s_TMPL : [ ' % tmp_name + '%s, %s, ' % (parts[1], cfg_tag) \
+ + ', '.join(parts[2:]) + ' ] }'
+ else:
+ sval = '!expand { %s_TMPL : [ ' % tmp_name + ', '.join(parts[1:]) + ' ] }'
+ config_dict.clear()
+ config_dict['cname'] = tmp_name
+ config_dict['expand'] = sval
+ return True
+ else:
+ if key in ['name', 'help', 'option'] and val.startswith('+'):
+ val = config_dict[key] + '\n' + val[1:]
+ if val.strip() == '':
+ val = "''"
+ config_dict[key] = val
+
+ else:
+ match = self.hdr_reg_exp.match(remaining)
+ if not match:
+ return False
+ key = match.group(1)
+ remaining = match.group(2)
+ if key == 'EMBED':
+ parts = remaining.split(':')
+ names = parts[0].split(',')
+ if parts[-1] == 'END':
+ prefix = '>'
+ else:
+ prefix = '<'
+ skip = False
+ if parts[1].startswith('TAG_'):
+ tag_txt = '%s:%s' % (names[0], parts[1])
+ else:
+ tag_txt = names[0]
+ if parts[2] in ['START', 'END']:
+ if names[0] == 'PCIE_RP_PIN_CTRL[]':
+ skip = True
+ else:
+ tag_txt = '%s:%s' % (names[0], parts[1])
+ if not skip:
+ config_dict.clear()
+ config_dict['cname'] = prefix + tag_txt
+ return True
+
+ if key == 'STRUCT':
+ text = remaining.strip()
+ config_dict[key.lower()] = text
+
+ return False
+
+ def process_template_lines(self, lines):
+ """
+ Process a line in DSC template section.
+ """
+ template_name = ''
+ bsf_temp_dict = OrderedDict()
+ temp_file_dict = OrderedDict()
+ include_file = ['.']
+
+ for line in lines:
+ match = re.match(r"^\s*#\s+!([<>])\s+include\s+(.+)", line)
+ if match:
+ if match.group(1) == '<':
+ include_file.append(match.group(2))
+ else:
+ include_file.pop()
+
+ match = re.match(r"^\s*#\s+(!BSF)\s+DEFT:{(.+?):(START|END)}", line)
+ if match:
+ if match.group(3) == 'START' and not template_name:
+ template_name = match.group(2).strip()
+ temp_file_dict[template_name] = list(include_file)
+ bsf_temp_dict[template_name] = []
+ if match.group(3) == 'END' and (template_name == match.group(2).strip()) \
+ and template_name:
+ template_name = ''
+ else:
+ if template_name:
+ bsf_temp_dict[template_name].append(line)
+ return bsf_temp_dict, temp_file_dict
+
+ def process_option_lines(self, lines):
+ """
+ Process a line in DSC config section.
+ """
+ cfgs = []
+ struct_end = False
+ config_dict = dict()
+ init_dict = dict()
+ include = ['']
+ for line in lines:
+ ret = self.parse_dsc_line(line, config_dict, init_dict, include)
+ if ret:
+ if 'padding' in init_dict:
+ num = init_dict['padding']
+ init_dict.clear()
+ padding_dict = {}
+ cfgs.append(padding_dict)
+ padding_dict['cname'] = 'UnusedUpdSpace%d' % self.unused_idx
+ padding_dict['length'] = '0x%x' % num
+ padding_dict['value'] = '{ 0 }'
+ self.unused_idx += 1
+
+ if cfgs and cfgs[-1]['cname'][0] != '@' and config_dict['cname'][0] == '@':
+ # it is a bit field, mark the previous one as virtual
+ cname = cfgs[-1]['cname']
+ new_cfg = dict(cfgs[-1])
+ new_cfg['cname'] = '@$STRUCT'
+ cfgs[-1].clear()
+ cfgs[-1]['cname'] = cname
+ cfgs.append(new_cfg)
+
+ if cfgs and cfgs[-1]['cname'] == 'CFGHDR' and config_dict['cname'][0] == '<':
+ # swap CfgHeader and the CFG_DATA order
+ if ':' in config_dict['cname']:
+ # replace the real TAG for CFG_DATA
+ cfgs[-1]['expand'] = cfgs[-1]['expand'].replace(
+ '_$FFF_', '0x%s' %
+ config_dict['cname'].split(':')[1][4:])
+ cfgs.insert(-1, config_dict)
+ else:
+ self.process_config(config_dict)
+ if struct_end:
+ struct_end = False
+ cfgs.insert(-1, config_dict)
+ else:
+ cfgs.append(config_dict)
+ if config_dict['cname'][0] == '>':
+ struct_end = True
+
+ config_dict = dict(init_dict)
+ return cfgs
+
+ def variable_fixup(self, each):
+ """
+ Fix up some variable definitions for SBL.
+ """
+ key = each
+ val = self.gen_cfg_data._MacroDict[each]
+ return key, val
+
+ def template_fixup(self, tmp_name, tmp_list):
+ """
+ Fix up some special config templates for SBL
+ """
+ return
+
+ def config_fixup(self, cfg_list):
+ """
+ Fix up some special config items for SBL.
+ """
+
+ # Insert FSPT_UPD/FSPM_UPD/FSPS_UPD tag so as to create C strcture
+ idxs = []
+ for idx, cfg in enumerate(cfg_list):
+ if cfg['cname'].startswith('<FSP_UPD_HEADER'):
+ idxs.append(idx)
+
+ if len(idxs) != 3:
+ return
+
+ # Handle insert backwards so that the index does not change in the loop
+ fsp_comp = 'SMT'
+ idx_comp = 0
+ for idx in idxs[::-1]:
+ # Add current FSP?_UPD start tag
+ cfgfig_dict = {}
+ cfgfig_dict['cname'] = '<FSP%s_UPD' % fsp_comp[idx_comp]
+ cfg_list.insert(idx, cfgfig_dict)
+ if idx_comp < 2:
+ # Add previous FSP?_UPD end tag
+ cfgfig_dict = {}
+ cfgfig_dict['cname'] = '>FSP%s_UPD' % fsp_comp[idx_comp + 1]
+ cfg_list.insert(idx, cfgfig_dict)
+ idx_comp += 1
+
+ # Add final FSPS_UPD end tag
+ cfgfig_dict = {}
+ cfgfig_dict['cname'] = '>FSP%s_UPD' % fsp_comp[0]
+ cfg_list.append(cfgfig_dict)
+
+ return
+
+ def get_section_range(self, section_name):
+ """
+ Extract line number range from config file for a given section name.
+ """
+ start = -1
+ end = -1
+ for idx, line in enumerate(self.gen_cfg_data._DscLines):
+ if start < 0 and line.startswith('[%s]' % section_name):
+ start = idx
+ elif start >= 0 and line.startswith('['):
+ end = idx
+ break
+ if start == -1:
+ start = 0
+ if end == -1:
+ end = len(self.gen_cfg_data._DscLines)
+ return start, end
+
+ def normalize_file_name(self, file, is_temp=False):
+ """
+ Normalize file name convention so that it is consistent.
+ """
+ if file.endswith('.dsc'):
+ file = file[:-4] + '.yaml'
+ dir_name = os.path.dirname(file)
+ base_name = os.path.basename(file)
+ if is_temp:
+ if 'Template_' not in file:
+ base_name = base_name.replace('Template', 'Template_')
+ else:
+ if 'CfgData_' not in file:
+ base_name = base_name.replace('CfgData', 'CfgData_')
+ if dir_name:
+ path = dir_name + '/' + base_name
+ else:
+ path = base_name
+ return path
+
+ def output_variable(self):
+ """
+ Output variable block into a line list.
+ """
+ lines = []
+ for each in self.gen_cfg_data._MacroDict:
+ key, value = self.variable_fixup(each)
+ lines.append('%-30s : %s' % (key, value))
+ return lines
+
+ def output_template(self):
+ """
+ Output template block into a line list.
+ """
+ self.offset = 0
+ self.base_offset = 0
+ start, end = self.get_section_range('PcdsDynamicVpd.Tmp')
+ bsf_temp_dict, temp_file_dict = self.process_template_lines(self.gen_cfg_data._DscLines[start:end])
+ template_dict = dict()
+ lines = []
+ file_lines = {}
+ last_file = '.'
+ file_lines[last_file] = []
+
+ for tmp_name in temp_file_dict:
+ temp_file_dict[tmp_name][-1] = self.normalize_file_name(temp_file_dict[tmp_name][-1], True)
+ if len(temp_file_dict[tmp_name]) > 1:
+ temp_file_dict[tmp_name][-2] = self.normalize_file_name(temp_file_dict[tmp_name][-2], True)
+
+ for tmp_name in bsf_temp_dict:
+ file = temp_file_dict[tmp_name][-1]
+ if last_file != file and len(temp_file_dict[tmp_name]) > 1:
+ inc_file = temp_file_dict[tmp_name][-2]
+ file_lines[inc_file].extend(['', '- !include %s' % temp_file_dict[tmp_name][-1], ''])
+ last_file = file
+ if file not in file_lines:
+ file_lines[file] = []
+ lines = file_lines[file]
+ text = bsf_temp_dict[tmp_name]
+ tmp_list = self.process_option_lines(text)
+ self.template_fixup(tmp_name, tmp_list)
+ template_dict[tmp_name] = tmp_list
+ lines.append('%s: >' % tmp_name)
+ lines.extend(self.output_dict(tmp_list, False)['.'])
+ lines.append('\n')
+ return file_lines
+
+ def output_config(self):
+ """
+ Output config block into a line list.
+ """
+ self.offset = 0
+ self.base_offset = 0
+ start, end = self.get_section_range('PcdsDynamicVpd.Upd')
+ cfgs = self.process_option_lines(self.gen_cfg_data._DscLines[start:end])
+ self.config_fixup(cfgs)
+ file_lines = self.output_dict(cfgs, True)
+ return file_lines
+
+ def output_dict(self, cfgs, is_configs):
+ """
+ Output one config item into a line list.
+ """
+ file_lines = {}
+ level = 0
+ file = '.'
+ for each in cfgs:
+ if 'length' in each and int(each['length'], 0) == 0:
+ continue
+
+ if 'include' in each:
+ if each['include']:
+ each['include'] = self.normalize_file_name(each['include'])
+ file_lines[file].extend(['', '- !include %s' % each['include'], ''])
+ file = each['include']
+ else:
+ file = '.'
+ continue
+
+ if file not in file_lines:
+ file_lines[file] = []
+
+ lines = file_lines[file]
+ name = each['cname']
+
+ prefix = name[0]
+ if prefix == '<':
+ level += 1
+
+ padding = ' ' * level
+ if prefix not in '<>@':
+ padding += ' '
+ else:
+ name = name[1:]
+ if prefix == '@':
+ padding += ' '
+
+ if ':' in name:
+ parts = name.split(':')
+ name = parts[0]
+
+ padding = padding[2:] if is_configs else padding
+
+ if prefix != '>':
+ if 'expand' in each:
+ lines.append('%s- %s' % (padding, each['expand']))
+ else:
+ lines.append('%s- %-12s :' % (padding, name))
+
+ for field in each:
+ if field in ['cname', 'expand', 'include']:
+ continue
+ value_str = self.format_value(field, each[field], padding + ' ' * 16)
+ full_line = ' %s %-12s : %s' % (padding, field, value_str)
+ lines.extend(full_line.splitlines())
+
+ if prefix == '>':
+ level -= 1
+ if level == 0:
+ lines.append('')
+
+ return file_lines
+
+
+def bsf_to_dsc(bsf_file, dsc_file):
+ fsp_dsc = CFspBsf2Dsc(bsf_file)
+ dsc_lines = fsp_dsc.get_dsc_lines()
+ fd = open(dsc_file, 'w')
+ fd.write('\n'.join(dsc_lines))
+ fd.close()
+ return
+
+
+def dsc_to_yaml(dsc_file, yaml_file):
+ dsc2yaml = CFspDsc2Yaml()
+ dsc2yaml.load_config_data_from_dsc(dsc_file)
+
+ cfgs = {}
+ for cfg in ['Template', 'Option']:
+ if cfg == 'Template':
+ file_lines = dsc2yaml.output_template()
+ else:
+ file_lines = dsc2yaml.output_config()
+ for file in file_lines:
+ lines = file_lines[file]
+ if file == '.':
+ cfgs[cfg] = lines
+ else:
+ if('/' in file or '\\' in file):
+ continue
+ file = os.path.basename(file)
+ fo = open(os.path.join(file), 'w')
+ fo.write(__copyright_tmp__ % (cfg, date.today().year) + '\n\n')
+ for line in lines:
+ fo.write(line + '\n')
+ fo.close()
+
+ variables = dsc2yaml.output_variable()
+ fo = open(yaml_file, 'w')
+ fo.write(__copyright_tmp__ % ('Default', date.today().year))
+ if len(variables) > 0:
+ fo.write('\n\nvariable:\n')
+ for line in variables:
+ fo.write(' ' + line + '\n')
+
+ fo.write('\n\ntemplate:\n')
+ for line in cfgs['Template']:
+ if line != '':
+ fo.write(' ' + line + '\n')
+
+ fo.write('\n\nconfigs:\n')
+ for line in cfgs['Option']:
+ if line != '':
+ fo.write(' ' + line + '\n')
+
+ fo.close()
+
+
+def get_fsp_name_from_path(bsf_file):
+ name = ''
+ parts = bsf_file.split(os.sep)
+ for part in parts:
+ if part.endswith('FspBinPkg'):
+ name = part[:-9]
+ break
+ if not name:
+ raise Exception('Could not get FSP name from file path!')
+ return name
+
+
+def usage():
+ print('\n'.join([
+ "FspDscBsf2Yaml Version 0.10",
+ "Usage:",
+ " FspDscBsf2Yaml BsfFile|DscFile YamlFile"
+ ]))
+
+
+def main():
+ #
+ # Parse the options and args
+ #
+ argc = len(sys.argv)
+ if argc < 3:
+ usage()
+ return 1
+
+ bsf_file = sys.argv[1]
+ yaml_file = sys.argv[2]
+ if os.path.isdir(yaml_file):
+ yaml_file = os.path.join(yaml_file, get_fsp_name_from_path(bsf_file) + '.yaml')
+
+ if bsf_file.endswith('.dsc'):
+ dsc_file = bsf_file
+ bsf_file = ''
+ else:
+ dsc_file = os.path.splitext(yaml_file)[0] + '.dsc'
+ bsf_to_dsc(bsf_file, dsc_file)
+
+ dsc_to_yaml(dsc_file, yaml_file)
+
+ print("'%s' was created successfully!" % yaml_file)
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())