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