diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py')
-rwxr-xr-x | src/VBox/Devices/EFI/Firmware/IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py | 884 |
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()) |