]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/FspDscBsf2Yaml.py
IntelFsp2Pkg: Add YAML file generation support
[mirror_edk2.git] / IntelFsp2Pkg / Tools / FspDscBsf2Yaml.py
1 #!/usr/bin/env python
2 ## @ FspDscBsf2Yaml.py
3 # This script convert DSC or BSF format file into YAML format
4 #
5 # Copyright(c) 2021, Intel Corporation. All rights reserved.<BR>
6 # SPDX-License-Identifier: BSD-2-Clause-Patent
7 #
8 ##
9
10 import os
11 import re
12 import sys
13 from datetime import date
14 from collections import OrderedDict
15 from functools import reduce
16
17 from GenCfgOpt import CGenCfgOpt
18
19 __copyright_tmp__ = """## @file
20 #
21 # YAML CFGDATA %s File.
22 #
23 # Copyright(c) %4d, Intel Corporation. All rights reserved.<BR>
24 # SPDX-License-Identifier: BSD-2-Clause-Patent
25 #
26 ##
27 """
28
29 __copyright_dsc__ = """## @file
30 #
31 # Copyright (c) %04d, Intel Corporation. All rights reserved.<BR>
32 # SPDX-License-Identifier: BSD-2-Clause-Patent
33 #
34 ##
35
36 [PcdsDynamicVpd.Upd]
37 #
38 # Global definitions in BSF
39 # !BSF BLOCK:{NAME:"FSP UPD Configuration", VER:"0.1"}
40 #
41
42 """
43
44
45 def Bytes2Val(Bytes):
46 return reduce(lambda x, y: (x << 8) | y, Bytes[::-1])
47
48
49 class CFspBsf2Dsc:
50
51 def __init__(self, bsf_file):
52 self.cfg_list = CFspBsf2Dsc.parse_bsf(bsf_file)
53
54 def get_dsc_lines(self):
55 return CFspBsf2Dsc.generate_dsc(self.cfg_list)
56
57 def save_dsc(self, dsc_file):
58 return CFspBsf2Dsc.generate_dsc(self.cfg_list, dsc_file)
59
60 @staticmethod
61 def parse_bsf(bsf_file):
62
63 fd = open(bsf_file, 'r')
64 bsf_txt = fd.read()
65 fd.close()
66
67 find_list = []
68 regex = re.compile(r'\s+Find\s+"(.*?)"(.*?)^\s+\$(.*?)\s+', re.S | re.MULTILINE)
69 for match in regex.finditer(bsf_txt):
70 find = match.group(1)
71 name = match.group(3)
72 if not name.endswith('_Revision'):
73 raise Exception("Unexpected CFG item following 'Find' !")
74 find_list.append((name, find))
75
76 idx = 0
77 count = 0
78 prefix = ''
79 chk_dict = {}
80 cfg_list = []
81 cfg_temp = {'find': '', 'cname': '', 'length': 0, 'value': '0', 'type': 'Reserved',
82 'embed': '', 'page': '', 'option': '', 'instance': 0}
83 regex = re.compile(r'^\s+(\$(.*?)|Skip)\s+(\d+)\s+bytes(\s+\$_DEFAULT_\s+=\s+(.+?))?$',
84 re.S | re.MULTILINE)
85
86 for match in regex.finditer(bsf_txt):
87 dlen = int(match.group(3))
88 if match.group(1) == 'Skip':
89 key = 'gPlatformFspPkgTokenSpaceGuid_BsfSkip%d' % idx
90 val = ', '.join(['%02X' % ord(i) for i in '\x00' * dlen])
91 idx += 1
92 option = '$SKIP'
93 else:
94 key = match.group(2)
95 val = match.group(5)
96 option = ''
97
98 cfg_item = dict(cfg_temp)
99 finds = [i for i in find_list if i[0] == key]
100 if len(finds) > 0:
101 if count >= 1:
102 # Append a dummy one
103 cfg_item['cname'] = 'Dummy'
104 cfg_list.append(dict(cfg_item))
105 cfg_list[-1]['embed'] = '%s:TAG_%03X:END' % (prefix, ord(prefix[-1]))
106 prefix = finds[0][1]
107 cfg_item['embed'] = '%s:TAG_%03X:START' % (prefix, ord(prefix[-1]))
108 cfg_item['find'] = prefix
109 cfg_item['cname'] = 'Signature'
110 cfg_item['length'] = len(finds[0][1])
111 cfg_item['value'] = '0x%X' % Bytes2Val(finds[0][1].encode('UTF-8'))
112 cfg_list.append(dict(cfg_item))
113 cfg_item = dict(cfg_temp)
114 find_list.pop(0)
115 count = 0
116
117 cfg_item['cname'] = key
118 cfg_item['length'] = dlen
119 cfg_item['value'] = val
120 cfg_item['option'] = option
121
122 if key not in chk_dict.keys():
123 chk_dict[key] = 0
124 else:
125 chk_dict[key] += 1
126 cfg_item['instance'] = chk_dict[key]
127
128 cfg_list.append(cfg_item)
129 count += 1
130
131 if prefix:
132 cfg_item = dict(cfg_temp)
133 cfg_item['cname'] = 'Dummy'
134 cfg_item['embed'] = '%s:%03X:END' % (prefix, ord(prefix[-1]))
135 cfg_list.append(cfg_item)
136
137 option_dict = {}
138 selreg = re.compile(r'\s+Selection\s*(.+?)\s*,\s*"(.*?)"$', re.S | re.MULTILINE)
139 regex = re.compile(r'^List\s&(.+?)$(.+?)^EndList$', re.S | re.MULTILINE)
140 for match in regex.finditer(bsf_txt):
141 key = match.group(1)
142 option_dict[key] = []
143 for select in selreg.finditer(match.group(2)):
144 option_dict[key].append((int(select.group(1), 0), select.group(2)))
145
146 chk_dict = {}
147 pagereg = re.compile(r'^Page\s"(.*?)"$(.+?)^EndPage$', re.S | re.MULTILINE)
148 for match in pagereg.finditer(bsf_txt):
149 page = match.group(1)
150 for line in match.group(2).splitlines():
151 match = re.match(r'\s+(Combo|EditNum)\s\$(.+?),\s"(.*?)",\s(.+?),$', line)
152 if match:
153 cname = match.group(2)
154 if cname not in chk_dict.keys():
155 chk_dict[cname] = 0
156 else:
157 chk_dict[cname] += 1
158 instance = chk_dict[cname]
159 cfg_idxs = [i for i, j in enumerate(cfg_list) if j['cname'] == cname and j['instance'] == instance]
160 if len(cfg_idxs) != 1:
161 raise Exception("Multiple CFG item '%s' found !" % cname)
162 cfg_item = cfg_list[cfg_idxs[0]]
163 cfg_item['page'] = page
164 cfg_item['type'] = match.group(1)
165 cfg_item['prompt'] = match.group(3)
166 cfg_item['range'] = None
167 if cfg_item['type'] == 'Combo':
168 cfg_item['option'] = option_dict[match.group(4)[1:]]
169 elif cfg_item['type'] == 'EditNum':
170 cfg_item['option'] = match.group(4)
171 match = re.match(r'\s+ Help\s"(.*?)"$', line)
172 if match:
173 cfg_item['help'] = match.group(1)
174
175 match = re.match(r'\s+"Valid\srange:\s(.*)"$', line)
176 if match:
177 parts = match.group(1).split()
178 cfg_item['option'] = (
179 (int(parts[0], 0), int(parts[2], 0), cfg_item['option']))
180
181 return cfg_list
182
183 @staticmethod
184 def generate_dsc(option_list, dsc_file=None):
185 dsc_lines = []
186 header = '%s' % (__copyright_dsc__ % date.today().year)
187 dsc_lines.extend(header.splitlines())
188
189 pages = []
190 for cfg_item in option_list:
191 if cfg_item['page'] and (cfg_item['page'] not in pages):
192 pages.append(cfg_item['page'])
193
194 page_id = 0
195 for page in pages:
196 dsc_lines.append(' # !BSF PAGES:{PG%02X::"%s"}' % (page_id, page))
197 page_id += 1
198 dsc_lines.append('')
199
200 last_page = ''
201 for option in option_list:
202 dsc_lines.append('')
203 default = option['value']
204 pos = option['cname'].find('_')
205 name = option['cname'][pos + 1:]
206
207 if option['find']:
208 dsc_lines.append(' # !BSF FIND:{%s}' % option['find'])
209 dsc_lines.append('')
210
211 if option['instance'] > 0:
212 name = name + '_%s' % option['instance']
213
214 if option['embed']:
215 dsc_lines.append(' # !HDR EMBED:{%s}' % option['embed'])
216
217 if option['type'] == 'Reserved':
218 dsc_lines.append(' # !BSF NAME:{Reserved} TYPE:{Reserved}')
219 if option['option'] == '$SKIP':
220 dsc_lines.append(' # !BSF OPTION:{$SKIP}')
221 else:
222 prompt = option['prompt']
223
224 if last_page != option['page']:
225 last_page = option['page']
226 dsc_lines.append(' # !BSF PAGE:{PG%02X}' % (pages.index(option['page'])))
227
228 if option['type'] == 'Combo':
229 dsc_lines.append(' # !BSF NAME:{%s} TYPE:{%s}' %
230 (prompt, option['type']))
231 ops = []
232 for val, text in option['option']:
233 ops.append('0x%x:%s' % (val, text))
234 dsc_lines.append(' # !BSF OPTION:{%s}' % (', '.join(ops)))
235 elif option['type'] == 'EditNum':
236 cfg_len = option['length']
237 if ',' in default and cfg_len > 8:
238 dsc_lines.append(' # !BSF NAME:{%s} TYPE:{Table}' % (prompt))
239 if cfg_len > 16:
240 cfg_len = 16
241 ops = []
242 for i in range(cfg_len):
243 ops.append('%X:1:HEX' % i)
244 dsc_lines.append(' # !BSF OPTION:{%s}' % (', '.join(ops)))
245 else:
246 dsc_lines.append(
247 ' # !BSF NAME:{%s} TYPE:{%s, %s,(0x%X, 0x%X)}' %
248 (prompt, option['type'], option['option'][2],
249 option['option'][0], option['option'][1]))
250 dsc_lines.append(' # !BSF HELP:{%s}' % option['help'])
251
252 if ',' in default:
253 default = '{%s}' % default
254 dsc_lines.append(' gCfgData.%-30s | * | 0x%04X | %s' %
255 (name, option['length'], default))
256
257 if dsc_file:
258 fd = open(dsc_file, 'w')
259 fd.write('\n'.join(dsc_lines))
260 fd.close()
261
262 return dsc_lines
263
264
265 class CFspDsc2Yaml():
266
267 def __init__(self):
268 self._Hdr_key_list = ['EMBED', 'STRUCT']
269 self._Bsf_key_list = ['NAME', 'HELP', 'TYPE', 'PAGE', 'PAGES', 'OPTION',
270 'CONDITION', 'ORDER', 'MARKER', 'SUBT', 'FIELD', 'FIND']
271 self.gen_cfg_data = None
272 self.cfg_reg_exp = re.compile(r"^([_a-zA-Z0-9$\(\)]+)\s*\|\s*(0x[0-9A-F]+|\*)\s*\|"
273 + r"\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)")
274 self.bsf_reg_exp = re.compile(r"(%s):{(.+?)}(?:$|\s+)" % '|'.join(self._Bsf_key_list))
275 self.hdr_reg_exp = re.compile(r"(%s):{(.+?)}" % '|'.join(self._Hdr_key_list))
276 self.prefix = ''
277 self.unused_idx = 0
278 self.offset = 0
279 self.base_offset = 0
280
281 def load_config_data_from_dsc(self, file_name):
282 """
283 Load and parse a DSC CFGDATA file.
284 """
285 gen_cfg_data = CGenCfgOpt('FSP')
286 if file_name.endswith('.dsc'):
287 # if gen_cfg_data.ParseDscFileYaml(file_name, '') != 0:
288 if gen_cfg_data.ParseDscFile(file_name, '') != 0:
289 raise Exception('DSC file parsing error !')
290 if gen_cfg_data.CreateVarDict() != 0:
291 raise Exception('DSC variable creation error !')
292 else:
293 raise Exception('Unsupported file "%s" !' % file_name)
294 gen_cfg_data.UpdateDefaultValue()
295 self.gen_cfg_data = gen_cfg_data
296
297 def print_dsc_line(self):
298 """
299 Debug function to print all DSC lines.
300 """
301 for line in self.gen_cfg_data._DscLines:
302 print(line)
303
304 def format_value(self, field, text, indent=''):
305 """
306 Format a CFGDATA item into YAML format.
307 """
308 if(not text.startswith('!expand')) and (': ' in text):
309 tgt = ':' if field == 'option' else '- '
310 text = text.replace(': ', tgt)
311 lines = text.splitlines()
312 if len(lines) == 1 and field != 'help':
313 return text
314 else:
315 return '>\n ' + '\n '.join([indent + i.lstrip() for i in lines])
316
317 def reformat_pages(self, val):
318 # Convert XXX:YYY into XXX::YYY format for page definition
319 parts = val.split(',')
320 if len(parts) <= 1:
321 return val
322
323 new_val = []
324 for each in parts:
325 nodes = each.split(':')
326 if len(nodes) == 2:
327 each = '%s::%s' % (nodes[0], nodes[1])
328 new_val.append(each)
329 ret = ','.join(new_val)
330 return ret
331
332 def reformat_struct_value(self, utype, val):
333 # Convert DSC UINT16/32/64 array into new format by
334 # adding prefix 0:0[WDQ] to provide hint to the array format
335 if utype in ['UINT16', 'UINT32', 'UINT64']:
336 if val and val[0] == '{' and val[-1] == '}':
337 if utype == 'UINT16':
338 unit = 'W'
339 elif utype == 'UINT32':
340 unit = 'D'
341 else:
342 unit = 'Q'
343 val = '{ 0:0%s, %s }' % (unit, val[1:-1])
344 return val
345
346 def process_config(self, cfg):
347 if 'page' in cfg:
348 cfg['page'] = self.reformat_pages(cfg['page'])
349
350 if 'struct' in cfg:
351 cfg['value'] = self.reformat_struct_value(cfg['struct'], cfg['value'])
352
353 def parse_dsc_line(self, dsc_line, config_dict, init_dict, include):
354 """
355 Parse a line in DSC and update the config dictionary accordingly.
356 """
357 init_dict.clear()
358 match = re.match(r'g(CfgData|\w+FspPkgTokenSpaceGuid)\.(.+)', dsc_line)
359 if match:
360 match = self.cfg_reg_exp.match(match.group(2))
361 if not match:
362 return False
363 config_dict['cname'] = self.prefix + match.group(1)
364 value = match.group(4).strip()
365 length = match.group(3).strip()
366 config_dict['length'] = length
367 config_dict['value'] = value
368 if match.group(2) == '*':
369 self.offset += int(length, 0)
370 else:
371 org_offset = int(match.group(2), 0)
372 if org_offset == 0:
373 self.base_offset = self.offset
374 offset = org_offset + self.base_offset
375 if self.offset != offset:
376 if offset > self.offset:
377 init_dict['padding'] = offset - self.offset
378 self.offset = offset + int(length, 0)
379 return True
380
381 match = re.match(r"^\s*#\s+!([<>])\s+include\s+(.+)", dsc_line)
382 if match and len(config_dict) == 0:
383 # !include should not be inside a config field
384 # if so, do not convert include into YAML
385 init_dict = dict(config_dict)
386 config_dict.clear()
387 config_dict['cname'] = '$ACTION'
388 if match.group(1) == '<':
389 config_dict['include'] = match.group(2)
390 else:
391 config_dict['include'] = ''
392 return True
393
394 match = re.match(r"^\s*#\s+(!BSF|!HDR)\s+(.+)", dsc_line)
395 if not match:
396 return False
397
398 remaining = match.group(2)
399 if match.group(1) == '!BSF':
400 result = self.bsf_reg_exp.findall(remaining)
401 if not result:
402 return False
403
404 for each in result:
405 key = each[0].lower()
406 val = each[1]
407 if key == 'field':
408 name = each[1]
409 if ':' not in name:
410 raise Exception('Incorrect bit field format !')
411 parts = name.split(':')
412 config_dict['length'] = parts[1]
413 config_dict['cname'] = '@' + parts[0]
414 return True
415 elif key in ['pages', 'page', 'find']:
416 init_dict = dict(config_dict)
417 config_dict.clear()
418 config_dict['cname'] = '$ACTION'
419 if key == 'find':
420 config_dict['find'] = val
421 else:
422 config_dict['page'] = val
423 return True
424 elif key == 'subt':
425 config_dict.clear()
426 parts = each[1].split(':')
427 tmp_name = parts[0][:-5]
428 if tmp_name == 'CFGHDR':
429 cfg_tag = '_$FFF_'
430 sval = '!expand { %s_TMPL : [ ' % tmp_name + '%s, %s, ' % (parts[1], cfg_tag) \
431 + ', '.join(parts[2:]) + ' ] }'
432 else:
433 sval = '!expand { %s_TMPL : [ ' % tmp_name + ', '.join(parts[1:]) + ' ] }'
434 config_dict.clear()
435 config_dict['cname'] = tmp_name
436 config_dict['expand'] = sval
437 return True
438 else:
439 if key in ['name', 'help', 'option'] and val.startswith('+'):
440 val = config_dict[key] + '\n' + val[1:]
441 if val.strip() == '':
442 val = "''"
443 config_dict[key] = val
444
445 else:
446 match = self.hdr_reg_exp.match(remaining)
447 if not match:
448 return False
449 key = match.group(1)
450 remaining = match.group(2)
451 if key == 'EMBED':
452 parts = remaining.split(':')
453 names = parts[0].split(',')
454 if parts[-1] == 'END':
455 prefix = '>'
456 else:
457 prefix = '<'
458 skip = False
459 if parts[1].startswith('TAG_'):
460 tag_txt = '%s:%s' % (names[0], parts[1])
461 else:
462 tag_txt = names[0]
463 if parts[2] in ['START', 'END']:
464 if names[0] == 'PCIE_RP_PIN_CTRL[]':
465 skip = True
466 else:
467 tag_txt = '%s:%s' % (names[0], parts[1])
468 if not skip:
469 config_dict.clear()
470 config_dict['cname'] = prefix + tag_txt
471 return True
472
473 if key == 'STRUCT':
474 text = remaining.strip()
475 config_dict[key.lower()] = text
476
477 return False
478
479 def process_template_lines(self, lines):
480 """
481 Process a line in DSC template section.
482 """
483 template_name = ''
484 bsf_temp_dict = OrderedDict()
485 temp_file_dict = OrderedDict()
486 include_file = ['.']
487
488 for line in lines:
489 match = re.match(r"^\s*#\s+!([<>])\s+include\s+(.+)", line)
490 if match:
491 if match.group(1) == '<':
492 include_file.append(match.group(2))
493 else:
494 include_file.pop()
495
496 match = re.match(r"^\s*#\s+(!BSF)\s+DEFT:{(.+?):(START|END)}", line)
497 if match:
498 if match.group(3) == 'START' and not template_name:
499 template_name = match.group(2).strip()
500 temp_file_dict[template_name] = list(include_file)
501 bsf_temp_dict[template_name] = []
502 if match.group(3) == 'END' and (template_name == match.group(2).strip()) \
503 and template_name:
504 template_name = ''
505 else:
506 if template_name:
507 bsf_temp_dict[template_name].append(line)
508 return bsf_temp_dict, temp_file_dict
509
510 def process_option_lines(self, lines):
511 """
512 Process a line in DSC config section.
513 """
514 cfgs = []
515 struct_end = False
516 config_dict = dict()
517 init_dict = dict()
518 include = ['']
519 for line in lines:
520 ret = self.parse_dsc_line(line, config_dict, init_dict, include)
521 if ret:
522 if 'padding' in init_dict:
523 num = init_dict['padding']
524 init_dict.clear()
525 padding_dict = {}
526 cfgs.append(padding_dict)
527 padding_dict['cname'] = 'UnusedUpdSpace%d' % self.unused_idx
528 padding_dict['length'] = '0x%x' % num
529 padding_dict['value'] = '{ 0 }'
530 self.unused_idx += 1
531
532 if cfgs and cfgs[-1]['cname'][0] != '@' and config_dict['cname'][0] == '@':
533 # it is a bit field, mark the previous one as virtual
534 cname = cfgs[-1]['cname']
535 new_cfg = dict(cfgs[-1])
536 new_cfg['cname'] = '@$STRUCT'
537 cfgs[-1].clear()
538 cfgs[-1]['cname'] = cname
539 cfgs.append(new_cfg)
540
541 if cfgs and cfgs[-1]['cname'] == 'CFGHDR' and config_dict['cname'][0] == '<':
542 # swap CfgHeader and the CFG_DATA order
543 if ':' in config_dict['cname']:
544 # replace the real TAG for CFG_DATA
545 cfgs[-1]['expand'] = cfgs[-1]['expand'].replace(
546 '_$FFF_', '0x%s' %
547 config_dict['cname'].split(':')[1][4:])
548 cfgs.insert(-1, config_dict)
549 else:
550 self.process_config(config_dict)
551 if struct_end:
552 struct_end = False
553 cfgs.insert(-1, config_dict)
554 else:
555 cfgs.append(config_dict)
556 if config_dict['cname'][0] == '>':
557 struct_end = True
558
559 config_dict = dict(init_dict)
560 return cfgs
561
562 def variable_fixup(self, each):
563 """
564 Fix up some variable definitions for SBL.
565 """
566 key = each
567 val = self.gen_cfg_data._MacroDict[each]
568 return key, val
569
570 def template_fixup(self, tmp_name, tmp_list):
571 """
572 Fix up some special config templates for SBL
573 """
574 return
575
576 def config_fixup(self, cfg_list):
577 """
578 Fix up some special config items for SBL.
579 """
580
581 # Insert FSPT_UPD/FSPM_UPD/FSPS_UPD tag so as to create C strcture
582 idxs = []
583 for idx, cfg in enumerate(cfg_list):
584 if cfg['cname'].startswith('<FSP_UPD_HEADER'):
585 idxs.append(idx)
586
587 if len(idxs) != 3:
588 return
589
590 # Handle insert backwards so that the index does not change in the loop
591 fsp_comp = 'SMT'
592 idx_comp = 0
593 for idx in idxs[::-1]:
594 # Add current FSP?_UPD start tag
595 cfgfig_dict = {}
596 cfgfig_dict['cname'] = '<FSP%s_UPD' % fsp_comp[idx_comp]
597 cfg_list.insert(idx, cfgfig_dict)
598 if idx_comp < 2:
599 # Add previous FSP?_UPD end tag
600 cfgfig_dict = {}
601 cfgfig_dict['cname'] = '>FSP%s_UPD' % fsp_comp[idx_comp + 1]
602 cfg_list.insert(idx, cfgfig_dict)
603 idx_comp += 1
604
605 # Add final FSPS_UPD end tag
606 cfgfig_dict = {}
607 cfgfig_dict['cname'] = '>FSP%s_UPD' % fsp_comp[0]
608 cfg_list.append(cfgfig_dict)
609
610 return
611
612 def get_section_range(self, section_name):
613 """
614 Extract line number range from config file for a given section name.
615 """
616 start = -1
617 end = -1
618 for idx, line in enumerate(self.gen_cfg_data._DscLines):
619 if start < 0 and line.startswith('[%s]' % section_name):
620 start = idx
621 elif start >= 0 and line.startswith('['):
622 end = idx
623 break
624 if start == -1:
625 start = 0
626 if end == -1:
627 end = len(self.gen_cfg_data._DscLines)
628 return start, end
629
630 def normalize_file_name(self, file, is_temp=False):
631 """
632 Normalize file name convention so that it is consistent.
633 """
634 if file.endswith('.dsc'):
635 file = file[:-4] + '.yaml'
636 dir_name = os.path.dirname(file)
637 base_name = os.path.basename(file)
638 if is_temp:
639 if 'Template_' not in file:
640 base_name = base_name.replace('Template', 'Template_')
641 else:
642 if 'CfgData_' not in file:
643 base_name = base_name.replace('CfgData', 'CfgData_')
644 if dir_name:
645 path = dir_name + '/' + base_name
646 else:
647 path = base_name
648 return path
649
650 def output_variable(self):
651 """
652 Output variable block into a line list.
653 """
654 lines = []
655 for each in self.gen_cfg_data._MacroDict:
656 key, value = self.variable_fixup(each)
657 lines.append('%-30s : %s' % (key, value))
658 return lines
659
660 def output_template(self):
661 """
662 Output template block into a line list.
663 """
664 self.offset = 0
665 self.base_offset = 0
666 start, end = self.get_section_range('PcdsDynamicVpd.Tmp')
667 bsf_temp_dict, temp_file_dict = self.process_template_lines(self.gen_cfg_data._DscLines[start:end])
668 template_dict = dict()
669 lines = []
670 file_lines = {}
671 last_file = '.'
672 file_lines[last_file] = []
673
674 for tmp_name in temp_file_dict:
675 temp_file_dict[tmp_name][-1] = self.normalize_file_name(temp_file_dict[tmp_name][-1], True)
676 if len(temp_file_dict[tmp_name]) > 1:
677 temp_file_dict[tmp_name][-2] = self.normalize_file_name(temp_file_dict[tmp_name][-2], True)
678
679 for tmp_name in bsf_temp_dict:
680 file = temp_file_dict[tmp_name][-1]
681 if last_file != file and len(temp_file_dict[tmp_name]) > 1:
682 inc_file = temp_file_dict[tmp_name][-2]
683 file_lines[inc_file].extend(['', '- !include %s' % temp_file_dict[tmp_name][-1], ''])
684 last_file = file
685 if file not in file_lines:
686 file_lines[file] = []
687 lines = file_lines[file]
688 text = bsf_temp_dict[tmp_name]
689 tmp_list = self.process_option_lines(text)
690 self.template_fixup(tmp_name, tmp_list)
691 template_dict[tmp_name] = tmp_list
692 lines.append('%s: >' % tmp_name)
693 lines.extend(self.output_dict(tmp_list, False)['.'])
694 lines.append('\n')
695 return file_lines
696
697 def output_config(self):
698 """
699 Output config block into a line list.
700 """
701 self.offset = 0
702 self.base_offset = 0
703 start, end = self.get_section_range('PcdsDynamicVpd.Upd')
704 cfgs = self.process_option_lines(self.gen_cfg_data._DscLines[start:end])
705 self.config_fixup(cfgs)
706 file_lines = self.output_dict(cfgs, True)
707 return file_lines
708
709 def output_dict(self, cfgs, is_configs):
710 """
711 Output one config item into a line list.
712 """
713 file_lines = {}
714 level = 0
715 file = '.'
716 for each in cfgs:
717 if 'length' in each and int(each['length'], 0) == 0:
718 continue
719
720 if 'include' in each:
721 if each['include']:
722 each['include'] = self.normalize_file_name(each['include'])
723 file_lines[file].extend(['', '- !include %s' % each['include'], ''])
724 file = each['include']
725 else:
726 file = '.'
727 continue
728
729 if file not in file_lines:
730 file_lines[file] = []
731
732 lines = file_lines[file]
733 name = each['cname']
734
735 prefix = name[0]
736 if prefix == '<':
737 level += 1
738
739 padding = ' ' * level
740 if prefix not in '<>@':
741 padding += ' '
742 else:
743 name = name[1:]
744 if prefix == '@':
745 padding += ' '
746
747 if ':' in name:
748 parts = name.split(':')
749 name = parts[0]
750
751 padding = padding[2:] if is_configs else padding
752
753 if prefix != '>':
754 if 'expand' in each:
755 lines.append('%s- %s' % (padding, each['expand']))
756 else:
757 lines.append('%s- %-12s :' % (padding, name))
758
759 for field in each:
760 if field in ['cname', 'expand', 'include']:
761 continue
762 value_str = self.format_value(field, each[field], padding + ' ' * 16)
763 full_line = ' %s %-12s : %s' % (padding, field, value_str)
764 lines.extend(full_line.splitlines())
765
766 if prefix == '>':
767 level -= 1
768 if level == 0:
769 lines.append('')
770
771 return file_lines
772
773
774 def bsf_to_dsc(bsf_file, dsc_file):
775 fsp_dsc = CFspBsf2Dsc(bsf_file)
776 dsc_lines = fsp_dsc.get_dsc_lines()
777 fd = open(dsc_file, 'w')
778 fd.write('\n'.join(dsc_lines))
779 fd.close()
780 return
781
782
783 def dsc_to_yaml(dsc_file, yaml_file):
784 dsc2yaml = CFspDsc2Yaml()
785 dsc2yaml.load_config_data_from_dsc(dsc_file)
786
787 cfgs = {}
788 for cfg in ['Template', 'Option']:
789 if cfg == 'Template':
790 file_lines = dsc2yaml.output_template()
791 else:
792 file_lines = dsc2yaml.output_config()
793 for file in file_lines:
794 lines = file_lines[file]
795 if file == '.':
796 cfgs[cfg] = lines
797 else:
798 if('/' in file or '\\' in file):
799 continue
800 file = os.path.basename(file)
801 fo = open(os.path.join(file), 'w')
802 fo.write(__copyright_tmp__ % (cfg, date.today().year) + '\n\n')
803 for line in lines:
804 fo.write(line + '\n')
805 fo.close()
806
807 variables = dsc2yaml.output_variable()
808 fo = open(yaml_file, 'w')
809 fo.write(__copyright_tmp__ % ('Default', date.today().year))
810 if len(variables) > 0:
811 fo.write('\n\nvariable:\n')
812 for line in variables:
813 fo.write(' ' + line + '\n')
814
815 fo.write('\n\ntemplate:\n')
816 for line in cfgs['Template']:
817 if line != '':
818 fo.write(' ' + line + '\n')
819
820 fo.write('\n\nconfigs:\n')
821 for line in cfgs['Option']:
822 if line != '':
823 fo.write(' ' + line + '\n')
824
825 fo.close()
826
827
828 def get_fsp_name_from_path(bsf_file):
829 name = ''
830 parts = bsf_file.split(os.sep)
831 for part in parts:
832 if part.endswith('FspBinPkg'):
833 name = part[:-9]
834 break
835 if not name:
836 raise Exception('Could not get FSP name from file path!')
837 return name
838
839
840 def usage():
841 print('\n'.join([
842 "FspDscBsf2Yaml Version 0.10",
843 "Usage:",
844 " FspDscBsf2Yaml BsfFile|DscFile YamlFile"
845 ]))
846
847
848 def main():
849 #
850 # Parse the options and args
851 #
852 argc = len(sys.argv)
853 if argc < 3:
854 usage()
855 return 1
856
857 bsf_file = sys.argv[1]
858 yaml_file = sys.argv[2]
859 if os.path.isdir(yaml_file):
860 yaml_file = os.path.join(yaml_file, get_fsp_name_from_path(bsf_file) + '.yaml')
861
862 if bsf_file.endswith('.dsc'):
863 dsc_file = bsf_file
864 bsf_file = ''
865 else:
866 dsc_file = os.path.splitext(yaml_file)[0] + '.dsc'
867 bsf_to_dsc(bsf_file, dsc_file)
868
869 dsc_to_yaml(dsc_file, yaml_file)
870
871 print("'%s' was created successfully!" % yaml_file)
872
873 return 0
874
875
876 if __name__ == '__main__':
877 sys.exit(main())