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