#!/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()) |