]>
git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py
3 # This script convert DSC or BSF format file into YAML format
5 # Copyright(c) 2021, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
14 from collections
import OrderedDict
15 from datetime
import date
17 from FspGenCfgData
import CFspBsf2Dsc
, CGenCfgData
19 __copyright_tmp__
= """## @file
21 # Slim Bootloader CFGDATA %s File.
23 # Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
24 # SPDX-License-Identifier: BSD-2-Clause-Patent
33 self
._Hdr
_key
_list
= ['EMBED', 'STRUCT']
34 self
._Bsf
_key
_list
= ['NAME', 'HELP', 'TYPE', 'PAGE', 'PAGES',
35 'OPTION', 'CONDITION', 'ORDER', 'MARKER',
36 'SUBT', 'FIELD', 'FIND']
37 self
.gen_cfg_data
= None
38 self
.cfg_reg_exp
= re
.compile(
39 "^([_a-zA-Z0-9$\\(\\)]+)\\s*\\|\\s*(0x[0-9A-F]+|\\*)"
40 "\\s*\\|\\s*(\\d+|0x[0-9a-fA-F]+)\\s*\\|\\s*(.+)")
41 self
.bsf_reg_exp
= re
.compile("(%s):{(.+?)}(?:$|\\s+)"
42 % '|'.join(self
._Bsf
_key
_list
))
43 self
.hdr_reg_exp
= re
.compile("(%s):{(.+?)}"
44 % '|'.join(self
._Hdr
_key
_list
))
50 def load_config_data_from_dsc(self
, file_name
):
52 Load and parse a DSC CFGDATA file.
54 gen_cfg_data
= CGenCfgData('FSP')
55 if file_name
.endswith('.dsc'):
56 if gen_cfg_data
.ParseDscFile(file_name
) != 0:
57 raise Exception('DSC file parsing error !')
58 if gen_cfg_data
.CreateVarDict() != 0:
59 raise Exception('DSC variable creation error !')
61 raise Exception('Unsupported file "%s" !' % file_name
)
62 gen_cfg_data
.UpdateDefaultValue()
63 self
.gen_cfg_data
= gen_cfg_data
65 def print_dsc_line(self
):
67 Debug function to print all DSC lines.
69 for line
in self
.gen_cfg_data
._DscLines
:
72 def format_value(self
, field
, text
, indent
=''):
74 Format a CFGDATA item into YAML format.
76 if (not text
.startswith('!expand')) and (': ' in text
):
77 tgt
= ':' if field
== 'option' else '- '
78 text
= text
.replace(': ', tgt
)
79 lines
= text
.splitlines()
80 if len(lines
) == 1 and field
!= 'help':
83 return '>\n ' + '\n '.join(
84 [indent
+ i
.lstrip() for i
in lines
])
86 def reformat_pages(self
, val
):
87 # Convert XXX:YYY into XXX::YYY format for page definition
88 parts
= val
.split(',')
94 nodes
= each
.split(':')
96 each
= '%s::%s' % (nodes
[0], nodes
[1])
98 ret
= ','.join(new_val
)
101 def reformat_struct_value(self
, utype
, val
):
102 # Convert DSC UINT16/32/64 array into new format by
103 # adding prefix 0:0[WDQ] to provide hint to the array format
104 if utype
in ['UINT16', 'UINT32', 'UINT64']:
105 if val
and val
[0] == '{' and val
[-1] == '}':
106 if utype
== 'UINT16':
108 elif utype
== 'UINT32':
112 val
= '{ 0:0%s, %s }' % (unit
, val
[1:-1])
115 def process_config(self
, cfg
):
117 cfg
['page'] = self
.reformat_pages(cfg
['page'])
120 cfg
['value'] = self
.reformat_struct_value(
121 cfg
['struct'], cfg
['value'])
123 def parse_dsc_line(self
, dsc_line
, config_dict
, init_dict
, include
):
125 Parse a line in DSC and update the config dictionary accordingly.
128 match
= re
.match('g(CfgData|\\w+FspPkgTokenSpaceGuid)\\.(.+)',
131 match
= self
.cfg_reg_exp
.match(match
.group(2))
134 config_dict
['cname'] = self
.prefix
+ match
.group(1)
135 value
= match
.group(4).strip()
136 length
= match
.group(3).strip()
137 config_dict
['length'] = length
138 config_dict
['value'] = value
139 if match
.group(2) == '*':
140 self
.offset
+= int(length
, 0)
142 org_offset
= int(match
.group(2), 0)
144 self
.base_offset
= self
.offset
145 offset
= org_offset
+ self
.base_offset
146 if self
.offset
!= offset
:
147 if offset
> self
.offset
:
148 init_dict
['padding'] = offset
- self
.offset
149 self
.offset
= offset
+ int(length
, 0)
152 match
= re
.match("^\\s*#\\s+!([<>])\\s+include\\s+(.+)", dsc_line
)
153 if match
and len(config_dict
) == 0:
154 # !include should not be inside a config field
155 # if so, do not convert include into YAML
156 init_dict
= dict(config_dict
)
158 config_dict
['cname'] = '$ACTION'
159 if match
.group(1) == '<':
160 config_dict
['include'] = match
.group(2)
162 config_dict
['include'] = ''
165 match
= re
.match("^\\s*#\\s+(!BSF|!HDR)\\s+(.+)", dsc_line
)
169 remaining
= match
.group(2)
170 if match
.group(1) == '!BSF':
171 result
= self
.bsf_reg_exp
.findall(remaining
)
176 key
= each
[0].lower()
181 raise Exception('Incorrect bit field format !')
182 parts
= name
.split(':')
183 config_dict
['length'] = parts
[1]
184 config_dict
['cname'] = '@' + parts
[0]
186 elif key
in ['pages', 'page', 'find']:
187 init_dict
= dict(config_dict
)
189 config_dict
['cname'] = '$ACTION'
191 config_dict
['find'] = val
193 config_dict
['page'] = val
197 parts
= each
[1].split(':')
198 tmp_name
= parts
[0][:-5]
199 if tmp_name
== 'CFGHDR':
201 sval
= '!expand { %s_TMPL : [ ' % \
202 tmp_name
+ '%s, %s, ' % (parts
[1], cfg_tag
) + \
203 ', '.join(parts
[2:]) + ' ] }'
205 sval
= '!expand { %s_TMPL : [ ' % \
206 tmp_name
+ ', '.join(parts
[1:]) + ' ] }'
208 config_dict
['cname'] = tmp_name
209 config_dict
['expand'] = sval
212 if key
in ['name', 'help', 'option'] and \
214 val
= config_dict
[key
] + '\n' + val
[1:]
215 if val
.strip() == '':
217 config_dict
[key
] = val
220 match
= self
.hdr_reg_exp
.match(remaining
)
224 remaining
= match
.group(2)
226 parts
= remaining
.split(':')
227 names
= parts
[0].split(',')
228 if parts
[-1] == 'END':
233 if parts
[1].startswith('TAG_'):
234 tag_txt
= '%s:%s' % (names
[0], parts
[1])
237 if parts
[2] in ['START', 'END']:
238 if names
[0] == 'PCIE_RP_PIN_CTRL[]':
241 tag_txt
= '%s:%s' % (names
[0], parts
[1])
244 config_dict
['cname'] = prefix
+ tag_txt
248 text
= remaining
.strip()
249 config_dict
[key
.lower()] = text
253 def process_template_lines(self
, lines
):
255 Process a line in DSC template section.
258 bsf_temp_dict
= OrderedDict()
259 temp_file_dict
= OrderedDict()
263 match
= re
.match("^\\s*#\\s+!([<>])\\s+include\\s+(.+)", line
)
265 if match
.group(1) == '<':
266 include_file
.append(match
.group(2))
271 "^\\s*#\\s+(!BSF)\\s+DEFT:{(.+?):(START|END)}", line
)
273 if match
.group(3) == 'START' and not template_name
:
274 template_name
= match
.group(2).strip()
275 temp_file_dict
[template_name
] = list(include_file
)
276 bsf_temp_dict
[template_name
] = []
277 if match
.group(3) == 'END' and \
278 (template_name
== match
.group(2).strip()) and \
283 bsf_temp_dict
[template_name
].append(line
)
284 return bsf_temp_dict
, temp_file_dict
286 def process_option_lines(self
, lines
):
288 Process a line in DSC config section.
296 ret
= self
.parse_dsc_line(line
, config_dict
, init_dict
, include
)
298 if 'padding' in init_dict
:
299 num
= init_dict
['padding']
302 cfgs
.append(padding_dict
)
303 padding_dict
['cname'] = 'UnusedUpdSpace%d' % \
305 padding_dict
['length'] = '0x%x' % num
306 padding_dict
['value'] = '{ 0 }'
309 if cfgs
and cfgs
[-1]['cname'][0] != '@' and \
310 config_dict
['cname'][0] == '@':
311 # it is a bit field, mark the previous one as virtual
312 cname
= cfgs
[-1]['cname']
313 new_cfg
= dict(cfgs
[-1])
314 new_cfg
['cname'] = '@$STRUCT'
316 cfgs
[-1]['cname'] = cname
319 if cfgs
and cfgs
[-1]['cname'] == 'CFGHDR' and \
320 config_dict
['cname'][0] == '<':
321 # swap CfgHeader and the CFG_DATA order
322 if ':' in config_dict
['cname']:
323 # replace the real TAG for CFG_DATA
324 cfgs
[-1]['expand'] = cfgs
[-1]['expand'].replace(
326 config_dict
['cname'].split(':')[1][4:])
327 cfgs
.insert(-1, config_dict
)
329 self
.process_config(config_dict
)
332 cfgs
.insert(-1, config_dict
)
334 cfgs
.append(config_dict
)
335 if config_dict
['cname'][0] == '>':
338 config_dict
= dict(init_dict
)
341 def variable_fixup(self
, each
):
343 Fix up some variable definitions for SBL.
346 val
= self
.gen_cfg_data
._MacroDict
[each
]
349 def template_fixup(self
, tmp_name
, tmp_list
):
351 Fix up some special config templates for SBL
355 def config_fixup(self
, cfg_list
):
357 Fix up some special config items for SBL.
360 # Insert FSPT_UPD/FSPM_UPD/FSPS_UPD tag so as to create C strcture
362 for idx
, cfg
in enumerate(cfg_list
):
363 if cfg
['cname'].startswith('<FSP_UPD_HEADER'):
369 # Handle insert backwards so that the index does not change in the loop
372 for idx
in idxs
[::-1]:
373 # Add current FSP?_UPD start tag
375 cfgfig_dict
['cname'] = '<FSP%s_UPD' % fsp_comp
[idx_comp
]
376 cfg_list
.insert(idx
, cfgfig_dict
)
378 # Add previous FSP?_UPD end tag
380 cfgfig_dict
['cname'] = '>FSP%s_UPD' % fsp_comp
[idx_comp
+ 1]
381 cfg_list
.insert(idx
, cfgfig_dict
)
384 # Add final FSPS_UPD end tag
386 cfgfig_dict
['cname'] = '>FSP%s_UPD' % fsp_comp
[0]
387 cfg_list
.append(cfgfig_dict
)
391 def get_section_range(self
, section_name
):
393 Extract line number range from config file for a given section name.
397 for idx
, line
in enumerate(self
.gen_cfg_data
._DscLines
):
398 if start
< 0 and line
.startswith('[%s]' % section_name
):
400 elif start
>= 0 and line
.startswith('['):
406 end
= len(self
.gen_cfg_data
._DscLines
)
409 def normalize_file_name(self
, file, is_temp
=False):
411 Normalize file name convention so that it is consistent.
413 if file.endswith('.dsc'):
414 file = file[:-4] + '.yaml'
415 dir_name
= os
.path
.dirname(file)
416 base_name
= os
.path
.basename(file)
418 if 'Template_' not in file:
419 base_name
= base_name
.replace('Template', 'Template_')
421 if 'CfgData_' not in file:
422 base_name
= base_name
.replace('CfgData', 'CfgData_')
424 path
= dir_name
+ '/' + base_name
429 def output_variable(self
):
431 Output variable block into a line list.
434 for each
in self
.gen_cfg_data
._MacroDict
:
435 key
, value
= self
.variable_fixup(each
)
436 lines
.append('%-30s : %s' % (key
, value
))
439 def output_template(self
):
441 Output template block into a line list.
445 start
, end
= self
.get_section_range('PcdsDynamicVpd.Tmp')
446 bsf_temp_dict
, temp_file_dict
= self
.process_template_lines(
447 self
.gen_cfg_data
._DscLines
[start
:end
])
448 template_dict
= dict()
452 file_lines
[last_file
] = []
454 for tmp_name
in temp_file_dict
:
455 temp_file_dict
[tmp_name
][-1] = self
.normalize_file_name(
456 temp_file_dict
[tmp_name
][-1], True)
457 if len(temp_file_dict
[tmp_name
]) > 1:
458 temp_file_dict
[tmp_name
][-2] = self
.normalize_file_name(
459 temp_file_dict
[tmp_name
][-2], True)
461 for tmp_name
in bsf_temp_dict
:
462 file = temp_file_dict
[tmp_name
][-1]
463 if last_file
!= file and len(temp_file_dict
[tmp_name
]) > 1:
464 inc_file
= temp_file_dict
[tmp_name
][-2]
465 file_lines
[inc_file
].extend(
466 ['', '- !include %s' % temp_file_dict
[tmp_name
][-1], ''])
468 if file not in file_lines
:
469 file_lines
[file] = []
470 lines
= file_lines
[file]
471 text
= bsf_temp_dict
[tmp_name
]
472 tmp_list
= self
.process_option_lines(text
)
473 self
.template_fixup(tmp_name
, tmp_list
)
474 template_dict
[tmp_name
] = tmp_list
475 lines
.append('%s: >' % tmp_name
)
476 lines
.extend(self
.output_dict(tmp_list
, False)['.'])
480 def output_config(self
):
482 Output config block into a line list.
486 start
, end
= self
.get_section_range('PcdsDynamicVpd.Upd')
487 cfgs
= self
.process_option_lines(
488 self
.gen_cfg_data
._DscLines
[start
:end
])
489 self
.config_fixup(cfgs
)
490 file_lines
= self
.output_dict(cfgs
, True)
493 def output_dict(self
, cfgs
, is_configs
):
495 Output one config item into a line list.
502 if not each
['length'].endswith('b') and int(each
['length'],
506 if 'include' in each
:
508 each
['include'] = self
.normalize_file_name(
510 file_lines
[file].extend(
511 ['', '- !include %s' % each
['include'], ''])
512 file = each
['include']
517 if file not in file_lines
:
518 file_lines
[file] = []
520 lines
= file_lines
[file]
527 padding
= ' ' * level
528 if prefix
not in '<>@':
536 parts
= name
.split(':')
539 padding
= padding
[2:] if is_configs
else padding
543 lines
.append('%s- %s' % (padding
, each
['expand']))
545 lines
.append('%s- %-12s :' % (padding
, name
))
548 if field
in ['cname', 'expand', 'include']:
550 value_str
= self
.format_value(
551 field
, each
[field
], padding
+ ' ' * 16)
552 full_line
= ' %s %-12s : %s' % (padding
, field
, value_str
)
553 lines
.extend(full_line
.splitlines())
563 def bsf_to_dsc(bsf_file
, dsc_file
):
564 fsp_dsc
= CFspBsf2Dsc(bsf_file
)
565 dsc_lines
= fsp_dsc
.get_dsc_lines()
566 fd
= open(dsc_file
, 'w')
567 fd
.write('\n'.join(dsc_lines
))
572 def dsc_to_yaml(dsc_file
, yaml_file
):
573 dsc2yaml
= CFspDsc2Yaml()
574 dsc2yaml
.load_config_data_from_dsc(dsc_file
)
577 for cfg
in ['Template', 'Option']:
578 if cfg
== 'Template':
579 file_lines
= dsc2yaml
.output_template()
581 file_lines
= dsc2yaml
.output_config()
582 for file in file_lines
:
583 lines
= file_lines
[file]
587 if ('/' in file or '\\' in file):
589 file = os
.path
.basename(file)
590 out_dir
= os
.path
.dirname(file)
591 fo
= open(os
.path
.join(out_dir
, file), 'w')
592 fo
.write(__copyright_tmp__
% (
593 cfg
, date
.today().year
) + '\n\n')
595 fo
.write(line
+ '\n')
598 variables
= dsc2yaml
.output_variable()
599 fo
= open(yaml_file
, 'w')
600 fo
.write(__copyright_tmp__
% ('Default', date
.today().year
))
601 if len(variables
) > 0:
602 fo
.write('\n\nvariable:\n')
603 for line
in variables
:
604 fo
.write(' ' + line
+ '\n')
606 fo
.write('\n\ntemplate:\n')
607 for line
in cfgs
['Template']:
608 fo
.write(' ' + line
+ '\n')
610 fo
.write('\n\nconfigs:\n')
611 for line
in cfgs
['Option']:
612 fo
.write(' ' + line
+ '\n')
617 def get_fsp_name_from_path(bsf_file
):
619 parts
= bsf_file
.split(os
.sep
)
621 if part
.endswith('FspBinPkg'):
625 raise Exception('Could not get FSP name from file path!')
631 "FspDscBsf2Yaml Version 0.10",
633 " FspDscBsf2Yaml BsfFile|DscFile YamlFile"
639 # Parse the options and args
646 bsf_file
= sys
.argv
[1]
647 yaml_file
= sys
.argv
[2]
648 if os
.path
.isdir(yaml_file
):
649 yaml_file
= os
.path
.join(
650 yaml_file
, get_fsp_name_from_path(bsf_file
) + '.yaml')
652 if bsf_file
.endswith('.dsc'):
656 dsc_file
= os
.path
.splitext(yaml_file
)[0] + '.dsc'
657 bsf_to_dsc(bsf_file
, dsc_file
)
659 dsc_to_yaml(dsc_file
, yaml_file
)
661 print("'%s' was created successfully!" % yaml_file
)
666 if __name__
== '__main__':