]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
IntelFsp2Pkg: Add Config Editor tool support
[mirror_edk2.git] / IntelFsp2Pkg / Tools / ConfigEditor / GenYamlCfg.py
1 # @ GenYamlCfg.py
2 #
3 # Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
4 # SPDX-License-Identifier: BSD-2-Clause-Patent
5 #
6 #
7
8 import os
9 import sys
10 import re
11 import marshal
12 import string
13 import operator as op
14 import ast
15 import tkinter.messagebox as messagebox
16
17 from datetime import date
18 from collections import OrderedDict
19 from CommonUtility import value_to_bytearray, value_to_bytes, \
20 bytes_to_value, get_bits_from_bytes, set_bits_to_bytes
21
22 # Generated file copyright header
23 __copyright_tmp__ = """/** @file
24
25 Platform Configuration %s File.
26
27 Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
28 SPDX-License-Identifier: BSD-2-Clause-Patent
29
30 This file is automatically generated. Please do NOT modify !!!
31
32 **/
33 """
34
35
36 def get_copyright_header(file_type, allow_modify=False):
37 file_description = {
38 'yaml': 'Boot Setting',
39 'dlt': 'Delta',
40 'inc': 'C Binary Blob',
41 'h': 'C Struct Header'
42 }
43 if file_type in ['yaml', 'dlt']:
44 comment_char = '#'
45 else:
46 comment_char = ''
47 lines = __copyright_tmp__.split('\n')
48 if allow_modify:
49 lines = [line for line in lines if 'Please do NOT modify' not in line]
50 copyright_hdr = '\n'.join('%s%s' % (comment_char, line)
51 for line in lines)[:-1] + '\n'
52 return copyright_hdr % (file_description[file_type], date.today().year)
53
54
55 def check_quote(text):
56 if (text[0] == "'" and text[-1] == "'") or (text[0] == '"'
57 and text[-1] == '"'):
58 return True
59 return False
60
61
62 def strip_quote(text):
63 new_text = text.strip()
64 if check_quote(new_text):
65 return new_text[1:-1]
66 return text
67
68
69 def strip_delimiter(text, delim):
70 new_text = text.strip()
71 if new_text:
72 if new_text[0] == delim[0] and new_text[-1] == delim[-1]:
73 return new_text[1:-1]
74 return text
75
76
77 def bytes_to_bracket_str(bytes):
78 return '{ %s }' % (', '.join('0x%02x' % i for i in bytes))
79
80
81 def array_str_to_value(val_str):
82 val_str = val_str.strip()
83 val_str = strip_delimiter(val_str, '{}')
84 val_str = strip_quote(val_str)
85 value = 0
86 for each in val_str.split(',')[::-1]:
87 each = each.strip()
88 value = (value << 8) | int(each, 0)
89 return value
90
91
92 def write_lines(lines, file):
93 fo = open(file, "w")
94 fo.write(''.join([x[0] for x in lines]))
95 fo.close()
96
97
98 def read_lines(file):
99 if not os.path.exists(file):
100 test_file = os.path.basename(file)
101 if os.path.exists(test_file):
102 file = test_file
103 fi = open(file, 'r')
104 lines = fi.readlines()
105 fi.close()
106 return lines
107
108
109 def expand_file_value(path, value_str):
110 result = bytearray()
111 match = re.match("\\{\\s*FILE:(.+)\\}", value_str)
112 if match:
113 file_list = match.group(1).split(',')
114 for file in file_list:
115 file = file.strip()
116 bin_path = os.path.join(path, file)
117 result.extend(bytearray(open(bin_path, 'rb').read()))
118 print('\n\n result ', result)
119 return result
120
121
122 class ExpressionEval(ast.NodeVisitor):
123 operators = {
124 ast.Add: op.add,
125 ast.Sub: op.sub,
126 ast.Mult: op.mul,
127 ast.Div: op.floordiv,
128 ast.Mod: op.mod,
129 ast.Eq: op.eq,
130 ast.NotEq: op.ne,
131 ast.Gt: op.gt,
132 ast.Lt: op.lt,
133 ast.GtE: op.ge,
134 ast.LtE: op.le,
135 ast.BitXor: op.xor,
136 ast.BitAnd: op.and_,
137 ast.BitOr: op.or_,
138 ast.Invert: op.invert,
139 ast.USub: op.neg
140 }
141
142 def __init__(self):
143 self._debug = False
144 self._expression = ''
145 self._namespace = {}
146 self._get_variable = None
147
148 def eval(self, expr, vars={}):
149 self._expression = expr
150 if type(vars) is dict:
151 self._namespace = vars
152 self._get_variable = None
153 else:
154 self._namespace = {}
155 self._get_variable = vars
156 node = ast.parse(self._expression, mode='eval')
157 result = self.visit(node.body)
158 if self._debug:
159 print('EVAL [ %s ] = %s' % (expr, str(result)))
160 return result
161
162 def visit_Name(self, node):
163 if self._get_variable is not None:
164 return self._get_variable(node.id)
165 else:
166 return self._namespace[node.id]
167
168 def visit_Num(self, node):
169 return node.n
170
171 def visit_NameConstant(self, node):
172 return node.value
173
174 def visit_BoolOp(self, node):
175 result = False
176 if isinstance(node.op, ast.And):
177 for value in node.values:
178 result = self.visit(value)
179 if not result:
180 break
181 elif isinstance(node.op, ast.Or):
182 for value in node.values:
183 result = self.visit(value)
184 if result:
185 break
186 return True if result else False
187
188 def visit_UnaryOp(self, node):
189 val = self.visit(node.operand)
190 return ExpressionEval.operators[type(node.op)](val)
191
192 def visit_BinOp(self, node):
193 lhs = self.visit(node.left)
194 rhs = self.visit(node.right)
195 return ExpressionEval.operators[type(node.op)](lhs, rhs)
196
197 def visit_Compare(self, node):
198 right = self.visit(node.left)
199 result = True
200 for operation, comp in zip(node.ops, node.comparators):
201 if not result:
202 break
203 left = right
204 right = self.visit(comp)
205 result = ExpressionEval.operators[type(operation)](left, right)
206 return result
207
208 def visit_Call(self, node):
209 if node.func.id in ['ternary']:
210 condition = self.visit(node.args[0])
211 val_true = self.visit(node.args[1])
212 val_false = self.visit(node.args[2])
213 return val_true if condition else val_false
214 elif node.func.id in ['offset', 'length']:
215 if self._get_variable is not None:
216 return self._get_variable(node.args[0].s, node.func.id)
217 else:
218 raise ValueError("Unsupported function: " + repr(node))
219
220 def generic_visit(self, node):
221 raise ValueError("malformed node or string: " + repr(node))
222
223
224 class CFG_YAML():
225 TEMPLATE = 'template'
226 CONFIGS = 'configs'
227 VARIABLE = 'variable'
228
229 def __init__(self):
230 self.log_line = False
231 self.allow_template = False
232 self.cfg_tree = None
233 self.tmp_tree = None
234 self.var_dict = None
235 self.def_dict = {}
236 self.yaml_path = ''
237 self.lines = []
238 self.full_lines = []
239 self.index = 0
240 self.re_expand = re.compile(
241 r'(.+:\s+|\s*\-\s*)!expand\s+\{\s*(\w+_TMPL)\s*:\s*\[(.+)]\s*\}')
242 self.re_include = re.compile(r'(.+:\s+|\s*\-\s*)!include\s+(.+)')
243
244 @staticmethod
245 def count_indent(line):
246 return next((i for i, c in enumerate(line) if not c.isspace()),
247 len(line))
248
249 @staticmethod
250 def substitue_args(text, arg_dict):
251 for arg in arg_dict:
252 text = text.replace('$' + arg, arg_dict[arg])
253 return text
254
255 @staticmethod
256 def dprint(*args):
257 pass
258
259 def process_include(self, line, insert=True):
260 match = self.re_include.match(line)
261 if not match:
262 raise Exception("Invalid !include format '%s' !" % line.strip())
263
264 prefix = match.group(1)
265 include = match.group(2)
266 if prefix.strip() == '-':
267 prefix = ''
268 adjust = 0
269 else:
270 adjust = 2
271
272 include = strip_quote(include)
273 request = CFG_YAML.count_indent(line) + adjust
274
275 if self.log_line:
276 # remove the include line itself
277 del self.full_lines[-1]
278
279 inc_path = os.path.join(self.yaml_path, include)
280 if not os.path.exists(inc_path):
281 # try relative path to project root
282 try_path = os.path.join(os.path.dirname(os.path.realpath(__file__)
283 ), "../..", include)
284 if os.path.exists(try_path):
285 inc_path = try_path
286 else:
287 raise Exception("ERROR: Cannot open file '%s'." % inc_path)
288
289 lines = read_lines(inc_path)
290 current = 0
291 same_line = False
292 for idx, each in enumerate(lines):
293 start = each.lstrip()
294 if start == '' or start[0] == '#':
295 continue
296
297 if start[0] == '>':
298 # append the content directly at the same line
299 same_line = True
300
301 start = idx
302 current = CFG_YAML.count_indent(each)
303 break
304
305 lines = lines[start+1:] if same_line else lines[start:]
306 leading = ''
307 if same_line:
308 request = len(prefix)
309 leading = '>'
310
311 lines = [prefix + '%s\n' % leading] + [' ' * request +
312 i[current:] for i in lines]
313 if insert:
314 self.lines = lines + self.lines
315
316 return lines
317
318 def process_expand(self, line):
319 match = self.re_expand.match(line)
320 if not match:
321 raise Exception("Invalid !expand format '%s' !" % line.strip())
322 lines = []
323 prefix = match.group(1)
324 temp_name = match.group(2)
325 args = match.group(3)
326
327 if prefix.strip() == '-':
328 indent = 0
329 else:
330 indent = 2
331 lines = self.process_expand_template(temp_name, prefix, args, indent)
332 self.lines = lines + self.lines
333
334 def process_expand_template(self, temp_name, prefix, args, indent=2):
335 # expand text with arg substitution
336 if temp_name not in self.tmp_tree:
337 raise Exception("Could not find template '%s' !" % temp_name)
338 parts = args.split(',')
339 parts = [i.strip() for i in parts]
340 num = len(parts)
341 arg_dict = dict(zip(['(%d)' % (i + 1) for i in range(num)], parts))
342 str_data = self.tmp_tree[temp_name]
343 text = DefTemplate(str_data).safe_substitute(self.def_dict)
344 text = CFG_YAML.substitue_args(text, arg_dict)
345 target = CFG_YAML.count_indent(prefix) + indent
346 current = CFG_YAML.count_indent(text)
347 padding = target * ' '
348 if indent == 0:
349 leading = []
350 else:
351 leading = [prefix + '\n']
352 text = leading + [(padding + i + '\n')[current:]
353 for i in text.splitlines()]
354 return text
355
356 def load_file(self, yaml_file):
357 self.index = 0
358 self.lines = read_lines(yaml_file)
359
360 def peek_line(self):
361 if len(self.lines) == 0:
362 return None
363 else:
364 return self.lines[0]
365
366 def put_line(self, line):
367 self.lines.insert(0, line)
368 if self.log_line:
369 del self.full_lines[-1]
370
371 def get_line(self):
372 if len(self.lines) == 0:
373 return None
374 else:
375 line = self.lines.pop(0)
376 if self.log_line:
377 self.full_lines.append(line.rstrip())
378 return line
379
380 def get_multiple_line(self, indent):
381 text = ''
382 newind = indent + 1
383 while True:
384 line = self.peek_line()
385 if line is None:
386 break
387 sline = line.strip()
388 if sline != '':
389 newind = CFG_YAML.count_indent(line)
390 if newind <= indent:
391 break
392 self.get_line()
393 if sline != '':
394 text = text + line
395 return text
396
397 def traverse_cfg_tree(self, handler):
398 def _traverse_cfg_tree(root, level=0):
399 # config structure
400 for key in root:
401 if type(root[key]) is OrderedDict:
402 level += 1
403 handler(key, root[key], level)
404 _traverse_cfg_tree(root[key], level)
405 level -= 1
406 _traverse_cfg_tree(self.cfg_tree)
407
408 def count(self):
409 def _count(name, cfgs, level):
410 num[0] += 1
411 num = [0]
412 self.traverse_cfg_tree(_count)
413 return num[0]
414
415 def parse(self, parent_name='', curr=None, level=0):
416 child = None
417 last_indent = None
418 key = ''
419 temp_chk = {}
420
421 while True:
422 line = self.get_line()
423 if line is None:
424 break
425
426 curr_line = line.strip()
427 if curr_line == '' or curr_line[0] == '#':
428 continue
429
430 indent = CFG_YAML.count_indent(line)
431 if last_indent is None:
432 last_indent = indent
433
434 if indent != last_indent:
435 # outside of current block, put the line back to queue
436 self.put_line(' ' * indent + curr_line)
437
438 if curr_line.endswith(': >'):
439 # multiline marker
440 old_count = len(self.full_lines)
441 line = self.get_multiple_line(indent)
442 if self.log_line and not self.allow_template \
443 and '!include ' in line:
444 # expand include in template
445 new_lines = []
446 lines = line.splitlines()
447 for idx, each in enumerate(lines):
448 if '!include ' in each:
449 new_line = ''.join(self.process_include(each,
450 False))
451 new_lines.append(new_line)
452 else:
453 new_lines.append(each)
454 self.full_lines = self.full_lines[:old_count] + new_lines
455 curr_line = curr_line + line
456
457 if indent > last_indent:
458 # child nodes
459 if child is None:
460 raise Exception('Unexpected format at line: %s'
461 % (curr_line))
462
463 level += 1
464 self.parse(key, child, level)
465 level -= 1
466 line = self.peek_line()
467 if line is not None:
468 curr_line = line.strip()
469 indent = CFG_YAML.count_indent(line)
470 if indent >= last_indent:
471 # consume the line
472 self.get_line()
473 else:
474 # end of file
475 indent = -1
476
477 if curr is None:
478 curr = OrderedDict()
479
480 if indent < last_indent:
481 return curr
482
483 marker1 = curr_line[0]
484 marker2 = curr_line[-1]
485 start = 1 if marker1 == '-' else 0
486 pos = curr_line.find(': ')
487 if pos > 0:
488 child = None
489 key = curr_line[start:pos].strip()
490 if curr_line[pos + 2] == '>':
491 curr[key] = curr_line[pos + 3:]
492 else:
493 # XXXX: !include / !expand
494 if '!include ' in curr_line:
495 self.process_include(line)
496 elif '!expand ' in curr_line:
497 if self.allow_template and not self.log_line:
498 self.process_expand(line)
499 else:
500 value_str = curr_line[pos + 2:].strip()
501 curr[key] = value_str
502 if self.log_line and value_str[0] == '{':
503 # expand {FILE: xxxx} format in the log line
504 if value_str[1:].rstrip().startswith('FILE:'):
505 value_bytes = expand_file_value(
506 self.yaml_path, value_str)
507 value_str = bytes_to_bracket_str(value_bytes)
508 self.full_lines[-1] = line[
509 :indent] + curr_line[:pos + 2] + value_str
510
511 elif marker2 == ':':
512 child = OrderedDict()
513 key = curr_line[start:-1].strip()
514 if key == '$ACTION':
515 # special virtual nodes, rename to ensure unique key
516 key = '$ACTION_%04X' % self.index
517 self.index += 1
518 if key in curr:
519 if key not in temp_chk:
520 # check for duplicated keys at same level
521 temp_chk[key] = 1
522 else:
523 raise Exception("Duplicated item '%s:%s' found !"
524 % (parent_name, key))
525
526 curr[key] = child
527 if self.var_dict is None and key == CFG_YAML.VARIABLE:
528 self.var_dict = child
529 if self.tmp_tree is None and key == CFG_YAML.TEMPLATE:
530 self.tmp_tree = child
531 if self.var_dict:
532 for each in self.var_dict:
533 txt = self.var_dict[each]
534 if type(txt) is str:
535 self.def_dict['(%s)' % each] = txt
536 if self.tmp_tree and key == CFG_YAML.CONFIGS:
537 # apply template for the main configs
538 self.allow_template = True
539 else:
540 child = None
541 # - !include cfg_opt.yaml
542 if '!include ' in curr_line:
543 self.process_include(line)
544
545 return curr
546
547 def load_yaml(self, opt_file):
548 self.var_dict = None
549 self.yaml_path = os.path.dirname(opt_file)
550 self.load_file(opt_file)
551 yaml_tree = self.parse()
552 self.tmp_tree = yaml_tree[CFG_YAML.TEMPLATE]
553 self.cfg_tree = yaml_tree[CFG_YAML.CONFIGS]
554 return self.cfg_tree
555
556 def expand_yaml(self, opt_file):
557 self.log_line = True
558 self.load_yaml(opt_file)
559 self.log_line = False
560 text = '\n'.join(self.full_lines)
561 self.full_lines = []
562 return text
563
564
565 class DefTemplate(string.Template):
566 idpattern = '\\([_A-Z][_A-Z0-9]*\\)|[_A-Z][_A-Z0-9]*'
567
568
569 class CGenYamlCfg:
570 STRUCT = '$STRUCT'
571 bits_width = {'b': 1, 'B': 8, 'W': 16, 'D': 32, 'Q': 64}
572 builtin_option = {'$EN_DIS': [('0', 'Disable'), ('1', 'Enable')]}
573 exclude_struct = ['FSP_UPD_HEADER', 'FSPT_ARCH_UPD',
574 'FSPM_ARCH_UPD', 'FSPS_ARCH_UPD',
575 'GPIO_GPP_*', 'GPIO_CFG_DATA',
576 'GpioConfPad*', 'GpioPinConfig',
577 'BOOT_OPTION*', 'PLATFORMID_CFG_DATA', '\\w+_Half[01]']
578 include_tag = ['GPIO_CFG_DATA']
579 keyword_set = set(['name', 'type', 'option', 'help', 'length',
580 'value', 'order', 'struct', 'condition'])
581
582 def __init__(self):
583 self._mode = ''
584 self._debug = False
585 self._macro_dict = {}
586 self.initialize()
587
588 def initialize(self):
589 self._old_bin = None
590 self._cfg_tree = {}
591 self._tmp_tree = {}
592 self._cfg_list = []
593 self._cfg_page = {'root': {'title': '', 'child': []}}
594 self._cur_page = ''
595 self._var_dict = {}
596 self._def_dict = {}
597 self._yaml_path = ''
598
599 @staticmethod
600 def deep_convert_dict(layer):
601 # convert OrderedDict to list + dict
602 new_list = layer
603 if isinstance(layer, OrderedDict):
604 new_list = list(layer.items())
605 for idx, pair in enumerate(new_list):
606 new_node = CGenYamlCfg.deep_convert_dict(pair[1])
607 new_list[idx] = dict({pair[0]: new_node})
608 return new_list
609
610 @staticmethod
611 def deep_convert_list(layer):
612 if isinstance(layer, list):
613 od = OrderedDict({})
614 for each in layer:
615 if isinstance(each, dict):
616 key = next(iter(each))
617 od[key] = CGenYamlCfg.deep_convert_list(each[key])
618 return od
619 else:
620 return layer
621
622 @staticmethod
623 def expand_include_files(file_path, cur_dir=''):
624 if cur_dir == '':
625 cur_dir = os.path.dirname(file_path)
626 file_path = os.path.basename(file_path)
627
628 input_file_path = os.path.join(cur_dir, file_path)
629 file = open(input_file_path, "r")
630 lines = file.readlines()
631 file.close()
632 new_lines = []
633 for line_num, line in enumerate(lines):
634 match = re.match("^!include\\s*(.+)?$", line.strip())
635 if match:
636 inc_path = match.group(1)
637 tmp_path = os.path.join(cur_dir, inc_path)
638 org_path = tmp_path
639 if not os.path.exists(tmp_path):
640 cur_dir = os.path.join(os.path.dirname
641 (os.path.realpath(__file__)
642 ), "..", "..")
643 tmp_path = os.path.join(cur_dir, inc_path)
644 if not os.path.exists(tmp_path):
645 raise Exception("ERROR: Cannot open include\
646 file '%s'." % org_path)
647 else:
648 new_lines.append(('# Included from file: %s\n' % inc_path,
649 tmp_path, 0))
650 new_lines.append(('# %s\n' % ('=' * 80), tmp_path, 0))
651 new_lines.extend(CGenYamlCfg.expand_include_files
652 (inc_path, cur_dir))
653 else:
654 new_lines.append((line, input_file_path, line_num))
655
656 return new_lines
657
658 @staticmethod
659 def format_struct_field_name(input, count=0):
660 name = ''
661 cap = True
662 if '_' in input:
663 input = input.lower()
664 for each in input:
665 if each == '_':
666 cap = True
667 continue
668 elif cap:
669 each = each.upper()
670 cap = False
671 name = name + each
672
673 if count > 1:
674 name = '%s[%d]' % (name, count)
675
676 return name
677
678 def get_mode(self):
679 return self._mode
680
681 def set_mode(self, mode):
682 self._mode = mode
683
684 def get_last_error(self):
685 return ''
686
687 def get_variable(self, var, attr='value'):
688 if var in self._var_dict:
689 var = self._var_dict[var]
690 return var
691
692 item = self.locate_cfg_item(var, False)
693 if item is None:
694 raise ValueError("Cannot find variable '%s' !" % var)
695
696 if item:
697 if 'indx' in item:
698 item = self.get_item_by_index(item['indx'])
699 if attr == 'offset':
700 var = item['offset']
701 elif attr == 'length':
702 var = item['length']
703 elif attr == 'value':
704 var = self.get_cfg_item_value(item)
705 else:
706 raise ValueError("Unsupported variable attribute '%s' !" %
707 attr)
708 return var
709
710 def eval(self, expr):
711 def _handler(pattern):
712 if pattern.group(1):
713 target = 1
714 else:
715 target = 2
716 result = self.get_variable(pattern.group(target))
717 if result is None:
718 raise ValueError('Unknown variable $(%s) !' %
719 pattern.group(target))
720 return hex(result)
721
722 expr_eval = ExpressionEval()
723 if '$' in expr:
724 # replace known variable first
725 expr = re.sub(r'\$\(([_a-zA-Z][\w\.]*)\)|\$([_a-zA-Z][\w\.]*)',
726 _handler, expr)
727 return expr_eval.eval(expr, self.get_variable)
728
729 def parse_macros(self, macro_def_str):
730 # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']
731 self._macro_dict = {}
732 is_expression = False
733 for macro in macro_def_str:
734 if macro.startswith('-D'):
735 is_expression = True
736 if len(macro) > 2:
737 macro = macro[2:]
738 else:
739 continue
740 if is_expression:
741 is_expression = False
742 match = re.match("(\\w+)=(.+)", macro)
743 if match:
744 self._macro_dict[match.group(1)] = match.group(2)
745 else:
746 match = re.match("(\\w+)", macro)
747 if match:
748 self._macro_dict[match.group(1)] = ''
749 if len(self._macro_dict) == 0:
750 error = 1
751 else:
752 error = 0
753 if self._debug:
754 print("INFO : Macro dictionary:")
755 for each in self._macro_dict:
756 print(" $(%s) = [ %s ]"
757 % (each, self._macro_dict[each]))
758 return error
759
760 def get_cfg_list(self, page_id=None):
761 if page_id is None:
762 # return full list
763 return self._cfg_list
764 else:
765 # build a new list for items under a page ID
766 cfgs = [i for i in self._cfg_list if i['cname'] and
767 (i['page'] == page_id)]
768 return cfgs
769
770 def get_cfg_page(self):
771 return self._cfg_page
772
773 def get_cfg_item_length(self, item):
774 return item['length']
775
776 def get_cfg_item_value(self, item, array=False):
777 value_str = item['value']
778 length = item['length']
779 return self.get_value(value_str, length, array)
780
781 def format_value_to_str(self, value, bit_length, old_value=''):
782 # value is always int
783 length = (bit_length + 7) // 8
784 fmt = ''
785 if old_value.startswith('0x'):
786 fmt = '0x'
787 elif old_value and (old_value[0] in ['"', "'", '{']):
788 fmt = old_value[0]
789 else:
790 fmt = ''
791
792 bvalue = value_to_bytearray(value, length)
793 if fmt in ['"', "'"]:
794 svalue = bvalue.rstrip(b'\x00').decode()
795 value_str = fmt + svalue + fmt
796 elif fmt == "{":
797 value_str = '{ ' + ', '.join(['0x%02x' % i for i in bvalue]) + ' }'
798 elif fmt == '0x':
799 hex_len = length * 2
800 if len(old_value) == hex_len + 2:
801 fstr = '0x%%0%dx' % hex_len
802 else:
803 fstr = '0x%x'
804 value_str = fstr % value
805 else:
806 if length <= 2:
807 value_str = '%d' % value
808 elif length <= 8:
809 value_str = '0x%x' % value
810 else:
811 value_str = '{ ' + ', '.join(['0x%02x' % i for i in
812 bvalue]) + ' }'
813 return value_str
814
815 def reformat_value_str(self, value_str, bit_length, old_value=None):
816 value = self.parse_value(value_str, bit_length, False)
817 if old_value is None:
818 old_value = value_str
819 new_value = self.format_value_to_str(value, bit_length, old_value)
820 return new_value
821
822 def get_value(self, value_str, bit_length, array=True):
823 value_str = value_str.strip()
824 if value_str[0] == "'" and value_str[-1] == "'" or \
825 value_str[0] == '"' and value_str[-1] == '"':
826 value_str = value_str[1:-1]
827 bvalue = bytearray(value_str.encode())
828 if len(bvalue) == 0:
829 bvalue = bytearray(b'\x00')
830 if array:
831 return bvalue
832 else:
833 return bytes_to_value(bvalue)
834 else:
835 if value_str[0] in '{':
836 value_str = value_str[1:-1].strip()
837 value = 0
838 for each in value_str.split(',')[::-1]:
839 each = each.strip()
840 value = (value << 8) | int(each, 0)
841 if array:
842 length = (bit_length + 7) // 8
843 return value_to_bytearray(value, length)
844 else:
845 return value
846
847 def parse_value(self, value_str, bit_length, array=True):
848 length = (bit_length + 7) // 8
849 if check_quote(value_str):
850 value_str = bytes_to_bracket_str(value_str[1:-1].encode())
851 elif (',' in value_str) and (value_str[0] != '{'):
852 value_str = '{ %s }' % value_str
853 if value_str[0] == '{':
854 result = expand_file_value(self._yaml_path, value_str)
855 if len(result) == 0:
856 bin_list = value_str[1:-1].split(',')
857 value = 0
858 bit_len = 0
859 unit_len = 1
860 for idx, element in enumerate(bin_list):
861 each = element.strip()
862 if len(each) == 0:
863 continue
864
865 in_bit_field = False
866 if each[0] in "'" + '"':
867 each_value = bytearray(each[1:-1], 'utf-8')
868 elif ':' in each:
869 match = re.match("^(.+):(\\d+)([b|B|W|D|Q])$", each)
870 if match is None:
871 raise SystemExit("Exception: Invald value\
872 list format '%s' !" % each)
873 if match.group(1) == '0' and match.group(2) == '0':
874 unit_len = CGenYamlCfg.bits_width[match.group(3)
875 ] // 8
876 cur_bit_len = int(match.group(2)
877 ) * CGenYamlCfg.bits_width[
878 match.group(3)]
879 value += ((self.eval(match.group(1)) & (
880 1 << cur_bit_len) - 1)) << bit_len
881 bit_len += cur_bit_len
882 each_value = bytearray()
883 if idx + 1 < len(bin_list):
884 in_bit_field = True
885 else:
886 try:
887 each_value = value_to_bytearray(
888 self.eval(each.strip()), unit_len)
889 except Exception:
890 raise SystemExit("Exception: Value %d cannot \
891 fit into %s bytes !" % (each, unit_len))
892
893 if not in_bit_field:
894 if bit_len > 0:
895 if bit_len % 8 != 0:
896 raise SystemExit("Exception: Invalid bit \
897 field alignment '%s' !" % value_str)
898 result.extend(value_to_bytes(value, bit_len // 8))
899 value = 0
900 bit_len = 0
901
902 result.extend(each_value)
903
904 elif check_quote(value_str):
905 result = bytearray(value_str[1:-1], 'utf-8') # Excluding quotes
906 else:
907 result = value_to_bytearray(self.eval(value_str), length)
908
909 if len(result) < length:
910 result.extend(b'\x00' * (length - len(result)))
911 elif len(result) > length:
912 raise SystemExit("Exception: Value '%s' is too big to fit \
913 into %d bytes !" % (value_str, length))
914
915 if array:
916 return result
917 else:
918 return bytes_to_value(result)
919
920 return result
921
922 def get_cfg_item_options(self, item):
923 tmp_list = []
924 if item['type'] == "Combo":
925 if item['option'] in CGenYamlCfg.builtin_option:
926 for op_val, op_str in CGenYamlCfg.builtin_option[item['option'
927 ]]:
928 tmp_list.append((op_val, op_str))
929 else:
930 opt_list = item['option'].split(',')
931 for option in opt_list:
932 option = option.strip()
933 try:
934 (op_val, op_str) = option.split(':')
935 except Exception:
936 raise SystemExit("Exception: Invalide \
937 option format '%s' !" % option)
938 tmp_list.append((op_val, op_str))
939 return tmp_list
940
941 def get_page_title(self, page_id, top=None):
942 if top is None:
943 top = self.get_cfg_page()['root']
944 for node in top['child']:
945 page_key = next(iter(node))
946 if page_id == page_key:
947 return node[page_key]['title']
948 else:
949 result = self.get_page_title(page_id, node[page_key])
950 if result is not None:
951 return result
952 return None
953
954 def print_pages(self, top=None, level=0):
955 if top is None:
956 top = self.get_cfg_page()['root']
957 for node in top['child']:
958 page_id = next(iter(node))
959 print('%s%s: %s' % (' ' * level, page_id, node[page_id]['title']))
960 level += 1
961 self.print_pages(node[page_id], level)
962 level -= 1
963
964 def get_item_by_index(self, index):
965 return self._cfg_list[index]
966
967 def get_item_by_path(self, path):
968 node = self.locate_cfg_item(path)
969 if node:
970 return self.get_item_by_index(node['indx'])
971 else:
972 return None
973
974 def locate_cfg_path(self, item):
975 def _locate_cfg_path(root, level=0):
976 # config structure
977 if item is root:
978 return path
979 for key in root:
980 if type(root[key]) is OrderedDict:
981 level += 1
982 path.append(key)
983 ret = _locate_cfg_path(root[key], level)
984 if ret:
985 return ret
986 path.pop()
987 return None
988 path = []
989 return _locate_cfg_path(self._cfg_tree)
990
991 def locate_cfg_item(self, path, allow_exp=True):
992 def _locate_cfg_item(root, path, level=0):
993 if len(path) == level:
994 return root
995 next_root = root.get(path[level], None)
996 if next_root is None:
997 if allow_exp:
998 raise Exception('Not a valid CFG config option path: %s' %
999 '.'.join(path[:level+1]))
1000 else:
1001 return None
1002 return _locate_cfg_item(next_root, path, level + 1)
1003
1004 path_nodes = path.split('.')
1005 return _locate_cfg_item(self._cfg_tree, path_nodes)
1006
1007 def traverse_cfg_tree(self, handler, top=None):
1008 def _traverse_cfg_tree(root, level=0):
1009 # config structure
1010 for key in root:
1011 if type(root[key]) is OrderedDict:
1012 level += 1
1013 handler(key, root[key], level)
1014 _traverse_cfg_tree(root[key], level)
1015 level -= 1
1016
1017 if top is None:
1018 top = self._cfg_tree
1019 _traverse_cfg_tree(top)
1020
1021 def print_cfgs(self, root=None, short=True, print_level=256):
1022 def _print_cfgs(name, cfgs, level):
1023
1024 if 'indx' in cfgs:
1025 act_cfg = self.get_item_by_index(cfgs['indx'])
1026 else:
1027 offset = 0
1028 length = 0
1029 value = ''
1030 if CGenYamlCfg.STRUCT in cfgs:
1031 cfg = cfgs[CGenYamlCfg.STRUCT]
1032 offset = int(cfg['offset'])
1033 length = int(cfg['length'])
1034 if 'value' in cfg:
1035 value = cfg['value']
1036 if length == 0:
1037 return
1038 act_cfg = dict({'value': value, 'offset': offset,
1039 'length': length})
1040 value = act_cfg['value']
1041 bit_len = act_cfg['length']
1042 offset = (act_cfg['offset'] + 7) // 8
1043 if value != '':
1044 try:
1045 value = self.reformat_value_str(act_cfg['value'],
1046 act_cfg['length'])
1047 except Exception:
1048 value = act_cfg['value']
1049 length = bit_len // 8
1050 bit_len = '(%db)' % bit_len if bit_len % 8 else '' * 4
1051 if level <= print_level:
1052 if short and len(value) > 40:
1053 value = '%s ... %s' % (value[:20], value[-20:])
1054 print('%04X:%04X%-6s %s%s : %s' % (offset, length, bit_len,
1055 ' ' * level, name, value))
1056
1057 self.traverse_cfg_tree(_print_cfgs)
1058
1059 def build_var_dict(self):
1060 def _build_var_dict(name, cfgs, level):
1061 if level <= 2:
1062 if CGenYamlCfg.STRUCT in cfgs:
1063 struct_info = cfgs[CGenYamlCfg.STRUCT]
1064 self._var_dict['_LENGTH_%s_' % name] = struct_info[
1065 'length'] // 8
1066 self._var_dict['_OFFSET_%s_' % name] = struct_info[
1067 'offset'] // 8
1068
1069 self._var_dict = {}
1070 self.traverse_cfg_tree(_build_var_dict)
1071 self._var_dict['_LENGTH_'] = self._cfg_tree[CGenYamlCfg.STRUCT][
1072 'length'] // 8
1073 return 0
1074
1075 def add_cfg_page(self, child, parent, title=''):
1076 def _add_cfg_page(cfg_page, child, parent):
1077 key = next(iter(cfg_page))
1078 if parent == key:
1079 cfg_page[key]['child'].append({child: {'title': title,
1080 'child': []}})
1081 return True
1082 else:
1083 result = False
1084 for each in cfg_page[key]['child']:
1085 if _add_cfg_page(each, child, parent):
1086 result = True
1087 break
1088 return result
1089
1090 return _add_cfg_page(self._cfg_page, child, parent)
1091
1092 def set_cur_page(self, page_str):
1093 if not page_str:
1094 return
1095
1096 if ',' in page_str:
1097 page_list = page_str.split(',')
1098 else:
1099 page_list = [page_str]
1100 for page_str in page_list:
1101 parts = page_str.split(':')
1102 if len(parts) in [1, 3]:
1103 page = parts[0].strip()
1104 if len(parts) == 3:
1105 # it is a new page definition, add it into tree
1106 parent = parts[1] if parts[1] else 'root'
1107 parent = parent.strip()
1108 if parts[2][0] == '"' and parts[2][-1] == '"':
1109 parts[2] = parts[2][1:-1]
1110
1111 if not self.add_cfg_page(page, parent, parts[2]):
1112 raise SystemExit("Error: Cannot find parent page \
1113 '%s'!" % parent)
1114 else:
1115 raise SystemExit("Error: Invalid page format '%s' !"
1116 % page_str)
1117 self._cur_page = page
1118
1119 def extend_variable(self, line):
1120 # replace all variables
1121 if line == '':
1122 return line
1123 loop = 2
1124 while loop > 0:
1125 line_after = DefTemplate(line).safe_substitute(self._def_dict)
1126 if line == line_after:
1127 break
1128 loop -= 1
1129 line = line_after
1130 return line_after
1131
1132 def reformat_number_per_type(self, itype, value):
1133 if check_quote(value) or value.startswith('{'):
1134 return value
1135 parts = itype.split(',')
1136 if len(parts) > 3 and parts[0] == 'EditNum':
1137 num_fmt = parts[1].strip()
1138 else:
1139 num_fmt = ''
1140 if num_fmt == 'HEX' and not value.startswith('0x'):
1141 value = '0x%X' % int(value, 10)
1142 elif num_fmt == 'DEC' and value.startswith('0x'):
1143 value = '%d' % int(value, 16)
1144 return value
1145
1146 def add_cfg_item(self, name, item, offset, path):
1147
1148 self.set_cur_page(item.get('page', ''))
1149
1150 if name[0] == '$':
1151 # skip all virtual node
1152 return 0
1153
1154 if not set(item).issubset(CGenYamlCfg.keyword_set):
1155 for each in list(item):
1156 if each not in CGenYamlCfg.keyword_set:
1157 raise Exception("Invalid attribute '%s' for '%s'!" %
1158 (each, '.'.join(path)))
1159
1160 length = item.get('length', 0)
1161 if type(length) is str:
1162 match = re.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)\\s*$", length)
1163 if match:
1164 unit_len = CGenYamlCfg.bits_width[match.group(2)]
1165 length = int(match.group(1), 10) * unit_len
1166 else:
1167 try:
1168 length = int(length, 0) * 8
1169 except Exception:
1170 raise Exception("Invalid length field '%s' for '%s' !" %
1171 (length, '.'.join(path)))
1172
1173 if offset % 8 > 0:
1174 raise Exception("Invalid alignment for field '%s' for \
1175 '%s' !" % (name, '.'.join(path)))
1176 else:
1177 # define is length in bytes
1178 length = length * 8
1179
1180 if not name.isidentifier():
1181 raise Exception("Invalid config name '%s' for '%s' !" %
1182 (name, '.'.join(path)))
1183
1184 itype = str(item.get('type', 'Reserved'))
1185 value = str(item.get('value', ''))
1186 if value:
1187 if not (check_quote(value) or value.startswith('{')):
1188 if ',' in value:
1189 value = '{ %s }' % value
1190 else:
1191 value = self.reformat_number_per_type(itype, value)
1192
1193 help = str(item.get('help', ''))
1194 if '\n' in help:
1195 help = ' '.join([i.strip() for i in help.splitlines()])
1196
1197 option = str(item.get('option', ''))
1198 if '\n' in option:
1199 option = ' '.join([i.strip() for i in option.splitlines()])
1200
1201 # extend variables for value and condition
1202 condition = str(item.get('condition', ''))
1203 if condition:
1204 condition = self.extend_variable(condition)
1205 value = self.extend_variable(value)
1206
1207 order = str(item.get('order', ''))
1208 if order:
1209 if '.' in order:
1210 (major, minor) = order.split('.')
1211 order = int(major, 16)
1212 else:
1213 order = int(order, 16)
1214 else:
1215 order = offset
1216
1217 cfg_item = dict()
1218 cfg_item['length'] = length
1219 cfg_item['offset'] = offset
1220 cfg_item['value'] = value
1221 cfg_item['type'] = itype
1222 cfg_item['cname'] = str(name)
1223 cfg_item['name'] = str(item.get('name', ''))
1224 cfg_item['help'] = help
1225 cfg_item['option'] = option
1226 cfg_item['page'] = self._cur_page
1227 cfg_item['order'] = order
1228 cfg_item['path'] = '.'.join(path)
1229 cfg_item['condition'] = condition
1230 if 'struct' in item:
1231 cfg_item['struct'] = item['struct']
1232 self._cfg_list.append(cfg_item)
1233
1234 item['indx'] = len(self._cfg_list) - 1
1235
1236 # remove used info for reducing pkl size
1237 item.pop('option', None)
1238 item.pop('condition', None)
1239 item.pop('help', None)
1240 item.pop('name', None)
1241 item.pop('page', None)
1242
1243 return length
1244
1245 def build_cfg_list(self, cfg_name='', top=None, path=[],
1246 info={'offset': 0}):
1247 if top is None:
1248 top = self._cfg_tree
1249 info.clear()
1250 info = {'offset': 0}
1251
1252 start = info['offset']
1253 is_leaf = True
1254 for key in top:
1255 path.append(key)
1256 if type(top[key]) is OrderedDict:
1257 is_leaf = False
1258 self.build_cfg_list(key, top[key], path, info)
1259 path.pop()
1260
1261 if is_leaf:
1262 length = self.add_cfg_item(cfg_name, top, info['offset'], path)
1263 info['offset'] += length
1264 elif cfg_name == '' or (cfg_name and cfg_name[0] != '$'):
1265 # check first element for struct
1266 first = next(iter(top))
1267 struct_str = CGenYamlCfg.STRUCT
1268 if first != struct_str:
1269 struct_node = OrderedDict({})
1270 top[struct_str] = struct_node
1271 top.move_to_end(struct_str, False)
1272 else:
1273 struct_node = top[struct_str]
1274 struct_node['offset'] = start
1275 struct_node['length'] = info['offset'] - start
1276 if struct_node['length'] % 8 != 0:
1277 raise SystemExit("Error: Bits length not aligned for %s !" %
1278 str(path))
1279
1280 def get_field_value(self, top=None):
1281 def _get_field_value(name, cfgs, level):
1282 if 'indx' in cfgs:
1283 act_cfg = self.get_item_by_index(cfgs['indx'])
1284 if act_cfg['length'] == 0:
1285 return
1286 value = self.get_value(act_cfg['value'], act_cfg['length'],
1287 False)
1288 set_bits_to_bytes(result, act_cfg['offset'] -
1289 struct_info['offset'], act_cfg['length'],
1290 value)
1291
1292 if top is None:
1293 top = self._cfg_tree
1294 struct_info = top[CGenYamlCfg.STRUCT]
1295 result = bytearray((struct_info['length'] + 7) // 8)
1296 self.traverse_cfg_tree(_get_field_value, top)
1297 return result
1298
1299 def set_field_value(self, top, value_bytes, force=False):
1300 def _set_field_value(name, cfgs, level):
1301 if 'indx' not in cfgs:
1302 return
1303 act_cfg = self.get_item_by_index(cfgs['indx'])
1304 if force or act_cfg['value'] == '':
1305 value = get_bits_from_bytes(full_bytes,
1306 act_cfg['offset'] -
1307 struct_info['offset'],
1308 act_cfg['length'])
1309 act_val = act_cfg['value']
1310 if act_val == '':
1311 act_val = '%d' % value
1312 act_val = self.reformat_number_per_type(act_cfg
1313 ['type'],
1314 act_val)
1315 act_cfg['value'] = self.format_value_to_str(
1316 value, act_cfg['length'], act_val)
1317
1318 if 'indx' in top:
1319 # it is config option
1320 value = bytes_to_value(value_bytes)
1321 act_cfg = self.get_item_by_index(top['indx'])
1322 act_cfg['value'] = self.format_value_to_str(
1323 value, act_cfg['length'], act_cfg['value'])
1324 else:
1325 # it is structure
1326 struct_info = top[CGenYamlCfg.STRUCT]
1327 length = struct_info['length'] // 8
1328 full_bytes = bytearray(value_bytes[:length])
1329 if len(full_bytes) < length:
1330 full_bytes.extend(bytearray(length - len(value_bytes)))
1331 self.traverse_cfg_tree(_set_field_value, top)
1332
1333 def update_def_value(self):
1334 def _update_def_value(name, cfgs, level):
1335 if 'indx' in cfgs:
1336 act_cfg = self.get_item_by_index(cfgs['indx'])
1337 if act_cfg['value'] != '' and act_cfg['length'] > 0:
1338 try:
1339 act_cfg['value'] = self.reformat_value_str(
1340 act_cfg['value'], act_cfg['length'])
1341 except Exception:
1342 raise Exception("Invalid value expression '%s' \
1343 for '%s' !" % (act_cfg['value'], act_cfg['path']))
1344 else:
1345 if CGenYamlCfg.STRUCT in cfgs and 'value' in \
1346 cfgs[CGenYamlCfg.STRUCT]:
1347 curr = cfgs[CGenYamlCfg.STRUCT]
1348 value_bytes = self.get_value(curr['value'],
1349 curr['length'], True)
1350 self.set_field_value(cfgs, value_bytes)
1351
1352 self.traverse_cfg_tree(_update_def_value, self._cfg_tree)
1353
1354 def evaluate_condition(self, item):
1355 expr = item['condition']
1356 result = self.parse_value(expr, 1, False)
1357 return result
1358
1359 def detect_fsp(self):
1360 cfg_segs = self.get_cfg_segment()
1361 if len(cfg_segs) == 3:
1362 fsp = True
1363 for idx, seg in enumerate(cfg_segs):
1364 if not seg[0].endswith('UPD_%s' % 'TMS'[idx]):
1365 fsp = False
1366 break
1367 else:
1368 fsp = False
1369 if fsp:
1370 self.set_mode('FSP')
1371 return fsp
1372
1373 def get_cfg_segment(self):
1374 def _get_cfg_segment(name, cfgs, level):
1375 if 'indx' not in cfgs:
1376 if name.startswith('$ACTION_'):
1377 if 'find' in cfgs:
1378 find[0] = cfgs['find']
1379 else:
1380 if find[0]:
1381 act_cfg = self.get_item_by_index(cfgs['indx'])
1382 segments.append([find[0], act_cfg['offset'] // 8, 0])
1383 find[0] = ''
1384 return
1385
1386 find = ['']
1387 segments = []
1388 self.traverse_cfg_tree(_get_cfg_segment, self._cfg_tree)
1389 cfg_len = self._cfg_tree[CGenYamlCfg.STRUCT]['length'] // 8
1390 if len(segments) == 0:
1391 segments.append(['', 0, cfg_len])
1392
1393 segments.append(['', cfg_len, 0])
1394 cfg_segs = []
1395 for idx, each in enumerate(segments[:-1]):
1396 cfg_segs.append((each[0], each[1],
1397 segments[idx+1][1] - each[1]))
1398
1399 return cfg_segs
1400
1401 def get_bin_segment(self, bin_data):
1402 cfg_segs = self.get_cfg_segment()
1403 bin_segs = []
1404 for seg in cfg_segs:
1405 key = seg[0].encode()
1406 if key == 0:
1407 bin_segs.append([seg[0], 0, len(bin_data)])
1408 break
1409 pos = bin_data.find(key)
1410 if pos >= 0:
1411 # ensure no other match for the key
1412 next_pos = bin_data.find(key, pos + len(seg[0]))
1413 if next_pos >= 0:
1414 if key == b'$SKLFSP$' or key == b'$BSWFSP$':
1415 string = ('Warning: Multiple matches for %s in '
1416 'binary!\n\nA workaround applied to such '
1417 'FSP 1.x binary to use second'
1418 ' match instead of first match!' % key)
1419 messagebox.showwarning('Warning!', string)
1420 pos = next_pos
1421 else:
1422 print("Warning: Multiple matches for '%s' "
1423 "in binary, the 1st instance will be used !"
1424 % seg[0])
1425 bin_segs.append([seg[0], pos, seg[2]])
1426 else:
1427 raise Exception("Could not find '%s' in binary !"
1428 % seg[0])
1429
1430 return bin_segs
1431
1432 def extract_cfg_from_bin(self, bin_data):
1433 # get cfg bin length
1434 cfg_bins = bytearray()
1435 bin_segs = self.get_bin_segment(bin_data)
1436 for each in bin_segs:
1437 cfg_bins.extend(bin_data[each[1]:each[1] + each[2]])
1438 return cfg_bins
1439
1440 def save_current_to_bin(self):
1441 cfg_bins = self.generate_binary_array()
1442 if self._old_bin is None:
1443 return cfg_bins
1444
1445 bin_data = bytearray(self._old_bin)
1446 bin_segs = self.get_bin_segment(self._old_bin)
1447 cfg_off = 0
1448 for each in bin_segs:
1449 length = each[2]
1450 bin_data[each[1]:each[1] + length] = cfg_bins[cfg_off:
1451 cfg_off
1452 + length]
1453 cfg_off += length
1454 print('Patched the loaded binary successfully !')
1455
1456 return bin_data
1457
1458 def load_default_from_bin(self, bin_data):
1459 self._old_bin = bin_data
1460 cfg_bins = self.extract_cfg_from_bin(bin_data)
1461 self.set_field_value(self._cfg_tree, cfg_bins, True)
1462 return cfg_bins
1463
1464 def generate_binary_array(self, path=''):
1465 if path == '':
1466 top = None
1467 else:
1468 top = self.locate_cfg_item(path)
1469 if not top:
1470 raise Exception("Invalid configuration path '%s' !"
1471 % path)
1472 return self.get_field_value(top)
1473
1474 def generate_binary(self, bin_file_name, path=''):
1475 bin_file = open(bin_file_name, "wb")
1476 bin_file.write(self.generate_binary_array(path))
1477 bin_file.close()
1478 return 0
1479
1480 def write_delta_file(self, out_file, platform_id, out_lines):
1481 dlt_fd = open(out_file, "w")
1482 dlt_fd.write("%s\n" % get_copyright_header('dlt', True))
1483 if platform_id is not None:
1484 dlt_fd.write('#\n')
1485 dlt_fd.write('# Delta configuration values for '
1486 'platform ID 0x%04X\n'
1487 % platform_id)
1488 dlt_fd.write('#\n\n')
1489 for line in out_lines:
1490 dlt_fd.write('%s\n' % line)
1491 dlt_fd.close()
1492
1493 def override_default_value(self, dlt_file):
1494 error = 0
1495 dlt_lines = CGenYamlCfg.expand_include_files(dlt_file)
1496
1497 platform_id = None
1498 for line, file_path, line_num in dlt_lines:
1499 line = line.strip()
1500 if not line or line.startswith('#'):
1501 continue
1502 match = re.match("\\s*([\\w\\.]+)\\s*\\|\\s*(.+)", line)
1503 if not match:
1504 raise Exception("Unrecognized line '%s' "
1505 "(File:'%s' Line:%d) !"
1506 % (line, file_path, line_num + 1))
1507
1508 path = match.group(1)
1509 value_str = match.group(2)
1510 top = self.locate_cfg_item(path)
1511 if not top:
1512 raise Exception(
1513 "Invalid configuration '%s' (File:'%s' Line:%d) !" %
1514 (path, file_path, line_num + 1))
1515
1516 if 'indx' in top:
1517 act_cfg = self.get_item_by_index(top['indx'])
1518 bit_len = act_cfg['length']
1519 else:
1520 struct_info = top[CGenYamlCfg.STRUCT]
1521 bit_len = struct_info['length']
1522
1523 value_bytes = self.parse_value(value_str, bit_len)
1524 self.set_field_value(top, value_bytes, True)
1525
1526 if path == 'PLATFORMID_CFG_DATA.PlatformId':
1527 platform_id = value_str
1528
1529 if platform_id is None:
1530 raise Exception(
1531 "PLATFORMID_CFG_DATA.PlatformId is missing "
1532 "in file '%s' !" %
1533 (dlt_file))
1534
1535 return error
1536
1537 def generate_delta_file_from_bin(self, delta_file, old_data,
1538 new_data, full=False):
1539 new_data = self.load_default_from_bin(new_data)
1540 lines = []
1541 platform_id = None
1542 def_platform_id = 0
1543
1544 for item in self._cfg_list:
1545 if not full and (item['type'] in ['Reserved']):
1546 continue
1547 old_val = get_bits_from_bytes(old_data, item['offset'],
1548 item['length'])
1549 new_val = get_bits_from_bytes(new_data, item['offset'],
1550 item['length'])
1551
1552 full_name = item['path']
1553 if 'PLATFORMID_CFG_DATA.PlatformId' == full_name:
1554 def_platform_id = old_val
1555 if new_val != old_val or full:
1556 val_str = self.reformat_value_str(item['value'],
1557 item['length'])
1558 text = '%-40s | %s' % (full_name, val_str)
1559 lines.append(text)
1560
1561 if self.get_mode() != 'FSP':
1562 if platform_id is None or def_platform_id == platform_id:
1563 platform_id = def_platform_id
1564 print("WARNING: 'PlatformId' configuration is "
1565 "same as default %d!" % platform_id)
1566
1567 lines.insert(0, '%-40s | %s\n\n' %
1568 ('PLATFORMID_CFG_DATA.PlatformId',
1569 '0x%04X' % platform_id))
1570 else:
1571 platform_id = None
1572
1573 self.write_delta_file(delta_file, platform_id, lines)
1574
1575 return 0
1576
1577 def generate_delta_file(self, delta_file, bin_file, bin_file2, full=False):
1578 fd = open(bin_file, 'rb')
1579 new_data = self.extract_cfg_from_bin(bytearray(fd.read()))
1580 fd.close()
1581
1582 if bin_file2 == '':
1583 old_data = self.generate_binary_array()
1584 else:
1585 old_data = new_data
1586 fd = open(bin_file2, 'rb')
1587 new_data = self.extract_cfg_from_bin(bytearray(fd.read()))
1588 fd.close()
1589
1590 return self.generate_delta_file_from_bin(delta_file,
1591 old_data, new_data, full)
1592
1593 def prepare_marshal(self, is_save):
1594 if is_save:
1595 # Ordered dict is not marshallable, convert to list
1596 self._cfg_tree = CGenYamlCfg.deep_convert_dict(self._cfg_tree)
1597 else:
1598 # Revert it back
1599 self._cfg_tree = CGenYamlCfg.deep_convert_list(self._cfg_tree)
1600
1601 def generate_yml_file(self, in_file, out_file):
1602 cfg_yaml = CFG_YAML()
1603 text = cfg_yaml.expand_yaml(in_file)
1604 yml_fd = open(out_file, "w")
1605 yml_fd.write(text)
1606 yml_fd.close()
1607 return 0
1608
1609 def write_cfg_header_file(self, hdr_file_name, tag_mode,
1610 tag_dict, struct_list):
1611 lines = []
1612 lines.append('\n\n')
1613 if self.get_mode() == 'FSP':
1614 lines.append('#include <FspUpd.h>\n')
1615
1616 tag_mode = tag_mode & 0x7F
1617 tag_list = sorted(list(tag_dict.items()), key=lambda x: x[1])
1618 for tagname, tagval in tag_list:
1619 if (tag_mode == 0 and tagval >= 0x100) or \
1620 (tag_mode == 1 and tagval < 0x100):
1621 continue
1622 lines.append('#define %-30s 0x%03X\n' % (
1623 'CDATA_%s_TAG' % tagname[:-9], tagval))
1624 lines.append('\n\n')
1625
1626 name_dict = {}
1627 new_dict = {}
1628 for each in struct_list:
1629 if (tag_mode == 0 and each['tag'] >= 0x100) or \
1630 (tag_mode == 1 and each['tag'] < 0x100):
1631 continue
1632 new_dict[each['name']] = (each['alias'], each['count'])
1633 if each['alias'] not in name_dict:
1634 name_dict[each['alias']] = 1
1635 lines.extend(self.create_struct(each['alias'],
1636 each['node'], new_dict))
1637 lines.append('#pragma pack()\n\n')
1638
1639 self.write_header_file(lines, hdr_file_name)
1640
1641 def write_header_file(self, txt_body, file_name, type='h'):
1642 file_name_def = os.path.basename(file_name).replace('.', '_')
1643 file_name_def = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', file_name_def)
1644 file_name_def = re.sub('([a-z0-9])([A-Z])', r'\1_\2',
1645 file_name_def).upper()
1646
1647 lines = []
1648 lines.append("%s\n" % get_copyright_header(type))
1649 lines.append("#ifndef __%s__\n" % file_name_def)
1650 lines.append("#define __%s__\n\n" % file_name_def)
1651 if type == 'h':
1652 lines.append("#pragma pack(1)\n\n")
1653 lines.extend(txt_body)
1654 if type == 'h':
1655 lines.append("#pragma pack()\n\n")
1656 lines.append("#endif\n")
1657
1658 # Don't rewrite if the contents are the same
1659 create = True
1660 if os.path.exists(file_name):
1661 hdr_file = open(file_name, "r")
1662 org_txt = hdr_file.read()
1663 hdr_file.close()
1664
1665 new_txt = ''.join(lines)
1666 if org_txt == new_txt:
1667 create = False
1668
1669 if create:
1670 hdr_file = open(file_name, "w")
1671 hdr_file.write(''.join(lines))
1672 hdr_file.close()
1673
1674 def generate_data_inc_file(self, dat_inc_file_name, bin_file=None):
1675 # Put a prefix GUID before CFGDATA so that it can be located later on
1676 prefix = b'\xa7\xbd\x7f\x73\x20\x1e\x46\xd6\
1677 xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
1678 if bin_file:
1679 fin = open(bin_file, 'rb')
1680 bin_dat = prefix + bytearray(fin.read())
1681 fin.close()
1682 else:
1683 bin_dat = prefix + self.generate_binary_array()
1684
1685 file_name = os.path.basename(dat_inc_file_name).upper()
1686 file_name = file_name.replace('.', '_')
1687
1688 txt_lines = []
1689
1690 txt_lines.append("UINT8 mConfigDataBlob[%d] = {\n" % len(bin_dat))
1691 count = 0
1692 line = [' ']
1693 for each in bin_dat:
1694 line.append('0x%02X, ' % each)
1695 count = count + 1
1696 if (count & 0x0F) == 0:
1697 line.append('\n')
1698 txt_lines.append(''.join(line))
1699 line = [' ']
1700 if len(line) > 1:
1701 txt_lines.append(''.join(line) + '\n')
1702
1703 txt_lines.append("};\n\n")
1704 self.write_header_file(txt_lines, dat_inc_file_name, 'inc')
1705
1706 return 0
1707
1708 def get_struct_array_info(self, input):
1709 parts = input.split(':')
1710 if len(parts) > 1:
1711 var = parts[1]
1712 input = parts[0]
1713 else:
1714 var = ''
1715 array_str = input.split('[')
1716 name = array_str[0]
1717 if len(array_str) > 1:
1718 num_str = ''.join(c for c in array_str[-1] if c.isdigit())
1719 num_str = '1000' if len(num_str) == 0 else num_str
1720 array_num = int(num_str)
1721 else:
1722 array_num = 0
1723 return name, array_num, var
1724
1725 def process_multilines(self, string, max_char_length):
1726 multilines = ''
1727 string_length = len(string)
1728 current_string_start = 0
1729 string_offset = 0
1730 break_line_dict = []
1731 if len(string) <= max_char_length:
1732 while (string_offset < string_length):
1733 if string_offset >= 1:
1734 if string[string_offset - 1] == '\\' and string[
1735 string_offset] == 'n':
1736 break_line_dict.append(string_offset + 1)
1737 string_offset += 1
1738 if break_line_dict != []:
1739 for each in break_line_dict:
1740 multilines += " %s\n" % string[
1741 current_string_start:each].lstrip()
1742 current_string_start = each
1743 if string_length - current_string_start > 0:
1744 multilines += " %s\n" % string[
1745 current_string_start:].lstrip()
1746 else:
1747 multilines = " %s\n" % string
1748 else:
1749 new_line_start = 0
1750 new_line_count = 0
1751 found_space_char = False
1752 while (string_offset < string_length):
1753 if string_offset >= 1:
1754 if new_line_count >= max_char_length - 1:
1755 if string[string_offset] == ' ' and \
1756 string_length - string_offset > 10:
1757 break_line_dict.append(new_line_start
1758 + new_line_count)
1759 new_line_start = new_line_start + new_line_count
1760 new_line_count = 0
1761 found_space_char = True
1762 elif string_offset == string_length - 1 and \
1763 found_space_char is False:
1764 break_line_dict.append(0)
1765 if string[string_offset - 1] == '\\' and string[
1766 string_offset] == 'n':
1767 break_line_dict.append(string_offset + 1)
1768 new_line_start = string_offset + 1
1769 new_line_count = 0
1770 string_offset += 1
1771 new_line_count += 1
1772 if break_line_dict != []:
1773 break_line_dict.sort()
1774 for each in break_line_dict:
1775 if each > 0:
1776 multilines += " %s\n" % string[
1777 current_string_start:each].lstrip()
1778 current_string_start = each
1779 if string_length - current_string_start > 0:
1780 multilines += " %s\n" % \
1781 string[current_string_start:].lstrip()
1782 return multilines
1783
1784 def create_field(self, item, name, length, offset, struct,
1785 bsf_name, help, option, bits_length=None):
1786 pos_name = 28
1787 name_line = ''
1788 # help_line = ''
1789 # option_line = ''
1790
1791 if length == 0 and name == 'dummy':
1792 return '\n'
1793
1794 if bits_length == 0:
1795 return '\n'
1796
1797 is_array = False
1798 if length in [1, 2, 4, 8]:
1799 type = "UINT%d" % (length * 8)
1800 else:
1801 is_array = True
1802 type = "UINT8"
1803
1804 if item and item['value'].startswith('{'):
1805 type = "UINT8"
1806 is_array = True
1807
1808 if struct != '':
1809 struct_base = struct.rstrip('*')
1810 name = '*' * (len(struct) - len(struct_base)) + name
1811 struct = struct_base
1812 type = struct
1813 if struct in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
1814 is_array = True
1815 unit = int(type[4:]) // 8
1816 length = length / unit
1817 else:
1818 is_array = False
1819
1820 if is_array:
1821 name = name + '[%d]' % length
1822
1823 if len(type) < pos_name:
1824 space1 = pos_name - len(type)
1825 else:
1826 space1 = 1
1827
1828 if bsf_name != '':
1829 name_line = " %s\n" % bsf_name
1830 else:
1831 name_line = "N/A\n"
1832
1833 # if help != '':
1834 # help_line = self.process_multilines(help, 80)
1835
1836 # if option != '':
1837 # option_line = self.process_multilines(option, 80)
1838
1839 if offset is None:
1840 offset_str = '????'
1841 else:
1842 offset_str = '0x%04X' % offset
1843
1844 if bits_length is None:
1845 bits_length = ''
1846 else:
1847 bits_length = ' : %d' % bits_length
1848
1849 # return "\n/** %s%s%s**/\n %s%s%s%s;\n" % (name_line, help_line,
1850 # option_line, type, ' ' * space1, name, bits_length)
1851 return "\n /* Offset %s: %s */\n %s%s%s%s;\n" % (
1852 offset_str, name_line.strip(), type, ' ' * space1,
1853 name, bits_length)
1854
1855 def create_struct(self, cname, top, struct_dict):
1856 index = 0
1857 last = ''
1858 lines = []
1859 off_base = -1
1860
1861 if cname in struct_dict:
1862 if struct_dict[cname][2]:
1863 return []
1864 lines.append('\ntypedef struct {\n')
1865 for field in top:
1866 if field[0] == '$':
1867 continue
1868
1869 index += 1
1870
1871 t_item = top[field]
1872 if 'indx' not in t_item:
1873 if CGenYamlCfg.STRUCT not in top[field]:
1874 continue
1875
1876 if struct_dict[field][1] == 0:
1877 continue
1878
1879 append = True
1880 struct_info = top[field][CGenYamlCfg.STRUCT]
1881
1882 if 'struct' in struct_info:
1883 struct, array_num, var = self.get_struct_array_info(
1884 struct_info['struct'])
1885 if array_num > 0:
1886 if last == struct:
1887 append = False
1888 last = struct
1889 if var == '':
1890 var = field
1891
1892 field = CGenYamlCfg.format_struct_field_name(
1893 var, struct_dict[field][1])
1894 else:
1895 struct = struct_dict[field][0]
1896 field = CGenYamlCfg.format_struct_field_name(
1897 field, struct_dict[field][1])
1898
1899 if append:
1900 offset = t_item['$STRUCT']['offset'] // 8
1901 if off_base == -1:
1902 off_base = offset
1903 line = self.create_field(None, field, 0, 0, struct,
1904 '', '', '')
1905 lines.append(' %s' % line)
1906 last = struct
1907 continue
1908
1909 item = self.get_item_by_index(t_item['indx'])
1910 if item['cname'] == 'CfgHeader' and index == 1 or \
1911 (item['cname'] == 'CondValue' and index == 2):
1912 continue
1913
1914 bit_length = None
1915 length = (item['length'] + 7) // 8
1916 match = re.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)",
1917 t_item['length'])
1918 if match and match.group(2) == 'b':
1919 bit_length = int(match.group(1))
1920 if match.group(3) != '':
1921 length = CGenYamlCfg.bits_width[match.group(3)] // 8
1922 else:
1923 length = 4
1924 offset = item['offset'] // 8
1925 if off_base == -1:
1926 off_base = offset
1927 struct = item.get('struct', '')
1928 name = field
1929 prompt = item['name']
1930 help = item['help']
1931 option = item['option']
1932 line = self.create_field(item, name, length, offset, struct,
1933 prompt, help, option, bit_length)
1934 lines.append(' %s' % line)
1935 last = struct
1936
1937 lines.append('\n} %s;\n\n' % cname)
1938
1939 return lines
1940
1941 def write_fsp_sig_header_file(self, hdr_file_name):
1942 hdr_fd = open(hdr_file_name, 'w')
1943 hdr_fd.write("%s\n" % get_copyright_header('h'))
1944 hdr_fd.write("#ifndef __FSPUPD_H__\n"
1945 "#define __FSPUPD_H__\n\n"
1946 "#include <FspEas.h>\n\n"
1947 "#pragma pack(1)\n\n")
1948 lines = []
1949 for fsp_comp in 'TMS':
1950 top = self.locate_cfg_item('FSP%s_UPD' % fsp_comp)
1951 if not top:
1952 raise Exception('Could not find FSP UPD definition !')
1953 bins = self.get_field_value(top)
1954 lines.append("#define FSP%s_UPD_SIGNATURE"
1955 " 0x%016X /* '%s' */\n\n"
1956 % (fsp_comp, bytes_to_value(bins[:8]),
1957 bins[:8].decode()))
1958 hdr_fd.write(''.join(lines))
1959 hdr_fd.write("#pragma pack()\n\n"
1960 "#endif\n")
1961 hdr_fd.close()
1962
1963 def create_header_file(self, hdr_file_name, com_hdr_file_name='', path=''):
1964
1965 def _build_header_struct(name, cfgs, level):
1966 if CGenYamlCfg.STRUCT in cfgs:
1967 if 'CfgHeader' in cfgs:
1968 # collect CFGDATA TAG IDs
1969 cfghdr = self.get_item_by_index(cfgs['CfgHeader']['indx'])
1970 tag_val = array_str_to_value(cfghdr['value']) >> 20
1971 tag_dict[name] = tag_val
1972 if level == 1:
1973 tag_curr[0] = tag_val
1974 struct_dict[name] = (level, tag_curr[0], cfgs)
1975 if path == 'FSP_SIG':
1976 self.write_fsp_sig_header_file(hdr_file_name)
1977 return
1978 tag_curr = [0]
1979 tag_dict = {}
1980 struct_dict = {}
1981
1982 if path == '':
1983 top = None
1984 else:
1985 top = self.locate_cfg_item(path)
1986 if not top:
1987 raise Exception("Invalid configuration path '%s' !" % path)
1988 _build_header_struct(path, top, 0)
1989 self.traverse_cfg_tree(_build_header_struct, top)
1990
1991 if tag_curr[0] == 0:
1992 hdr_mode = 2
1993 else:
1994 hdr_mode = 1
1995
1996 if re.match('FSP[TMS]_UPD', path):
1997 hdr_mode |= 0x80
1998
1999 # filter out the items to be built for tags and structures
2000 struct_list = []
2001 for each in struct_dict:
2002 match = False
2003 for check in CGenYamlCfg.exclude_struct:
2004 if re.match(check, each):
2005 match = True
2006 if each in tag_dict:
2007 if each not in CGenYamlCfg.include_tag:
2008 del tag_dict[each]
2009 break
2010 if not match:
2011 struct_list.append({'name': each, 'alias': '', 'count': 0,
2012 'level': struct_dict[each][0],
2013 'tag': struct_dict[each][1],
2014 'node': struct_dict[each][2]})
2015
2016 # sort by level so that the bottom level struct
2017 # will be build first to satisfy dependencies
2018 struct_list = sorted(struct_list, key=lambda x: x['level'],
2019 reverse=True)
2020
2021 # Convert XXX_[0-9]+ to XXX as an array hint
2022 for each in struct_list:
2023 cfgs = each['node']
2024 if 'struct' in cfgs['$STRUCT']:
2025 each['alias'], array_num, var = self.get_struct_array_info(
2026 cfgs['$STRUCT']['struct'])
2027 else:
2028 match = re.match('(\\w+)(_\\d+)', each['name'])
2029 if match:
2030 each['alias'] = match.group(1)
2031 else:
2032 each['alias'] = each['name']
2033
2034 # count items for array build
2035 for idx, each in enumerate(struct_list):
2036 if idx > 0:
2037 last_struct = struct_list[idx-1]['node']['$STRUCT']
2038 curr_struct = each['node']['$STRUCT']
2039 if struct_list[idx-1]['alias'] == each['alias'] and \
2040 curr_struct['length'] == last_struct['length'] and \
2041 curr_struct['offset'] == last_struct['offset'] + \
2042 last_struct['length']:
2043 for idx2 in range(idx-1, -1, -1):
2044 if struct_list[idx2]['count'] > 0:
2045 struct_list[idx2]['count'] += 1
2046 break
2047 continue
2048 each['count'] = 1
2049
2050 # generate common header
2051 if com_hdr_file_name:
2052 self.write_cfg_header_file(com_hdr_file_name, 0, tag_dict,
2053 struct_list)
2054
2055 # generate platform header
2056 self.write_cfg_header_file(hdr_file_name, hdr_mode, tag_dict,
2057 struct_list)
2058
2059 return 0
2060
2061 def load_yaml(self, cfg_file):
2062 cfg_yaml = CFG_YAML()
2063 self.initialize()
2064 self._cfg_tree = cfg_yaml.load_yaml(cfg_file)
2065 self._def_dict = cfg_yaml.def_dict
2066 self._yaml_path = os.path.dirname(cfg_file)
2067 self.build_cfg_list()
2068 self.build_var_dict()
2069 self.update_def_value()
2070 return 0
2071
2072
2073 def usage():
2074 print('\n'.join([
2075 "GenYamlCfg Version 0.50",
2076 "Usage:",
2077 " GenYamlCfg GENINC BinFile IncOutFile "
2078 " [-D Macros]",
2079
2080 " GenYamlCfg GENPKL YamlFile PklOutFile "
2081 " [-D Macros]",
2082 " GenYamlCfg GENBIN YamlFile[;DltFile] BinOutFile "
2083 " [-D Macros]",
2084 " GenYamlCfg GENDLT YamlFile[;BinFile] DltOutFile "
2085 " [-D Macros]",
2086 " GenYamlCfg GENYML YamlFile YamlOutFile"
2087 " [-D Macros]",
2088 " GenYamlCfg GENHDR YamlFile HdrOutFile "
2089 " [-D Macros]"
2090 ]))
2091
2092
2093 def main():
2094 # Parse the options and args
2095 argc = len(sys.argv)
2096 if argc < 4:
2097 usage()
2098 return 1
2099
2100 gen_cfg_data = CGenYamlCfg()
2101 command = sys.argv[1].upper()
2102 out_file = sys.argv[3]
2103 if argc >= 5 and gen_cfg_data.parse_macros(sys.argv[4:]) != 0:
2104 raise Exception("ERROR: Macro parsing failed !")
2105
2106 file_list = sys.argv[2].split(';')
2107 if len(file_list) >= 2:
2108 yml_file = file_list[0]
2109 dlt_file = file_list[1]
2110 elif len(file_list) == 1:
2111 yml_file = file_list[0]
2112 dlt_file = ''
2113 else:
2114 raise Exception("ERROR: Invalid parameter '%s' !" % sys.argv[2])
2115 yml_scope = ''
2116 if '@' in yml_file:
2117 parts = yml_file.split('@')
2118 yml_file = parts[0]
2119 yml_scope = parts[1]
2120
2121 if command == "GENDLT" and yml_file.endswith('.dlt'):
2122 # It needs to expand an existing DLT file
2123 dlt_file = yml_file
2124 lines = gen_cfg_data.expand_include_files(dlt_file)
2125 write_lines(lines, out_file)
2126 return 0
2127
2128 if command == "GENYML":
2129 if not yml_file.lower().endswith('.yaml'):
2130 raise Exception('Only YAML file is supported !')
2131 gen_cfg_data.generate_yml_file(yml_file, out_file)
2132 return 0
2133
2134 bin_file = ''
2135 if (yml_file.lower().endswith('.bin')) and (command == "GENINC"):
2136 # It is binary file
2137 bin_file = yml_file
2138 yml_file = ''
2139
2140 if bin_file:
2141 gen_cfg_data.generate_data_inc_file(out_file, bin_file)
2142 return 0
2143
2144 cfg_bin_file = ''
2145 cfg_bin_file2 = ''
2146 if dlt_file:
2147 if command == "GENDLT":
2148 cfg_bin_file = dlt_file
2149 dlt_file = ''
2150 if len(file_list) >= 3:
2151 cfg_bin_file2 = file_list[2]
2152
2153 if yml_file.lower().endswith('.pkl'):
2154 with open(yml_file, "rb") as pkl_file:
2155 gen_cfg_data.__dict__ = marshal.load(pkl_file)
2156 gen_cfg_data.prepare_marshal(False)
2157
2158 # Override macro definition again for Pickle file
2159 if argc >= 5:
2160 gen_cfg_data.parse_macros(sys.argv[4:])
2161 else:
2162 gen_cfg_data.load_yaml(yml_file)
2163 if command == 'GENPKL':
2164 gen_cfg_data.prepare_marshal(True)
2165 with open(out_file, "wb") as pkl_file:
2166 marshal.dump(gen_cfg_data.__dict__, pkl_file)
2167 json_file = os.path.splitext(out_file)[0] + '.json'
2168 fo = open(json_file, 'w')
2169 path_list = []
2170 cfgs = {'_cfg_page': gen_cfg_data._cfg_page,
2171 '_cfg_list': gen_cfg_data._cfg_list,
2172 '_path_list': path_list}
2173 # optimize to reduce size
2174 path = None
2175 for each in cfgs['_cfg_list']:
2176 new_path = each['path'][:-len(each['cname'])-1]
2177 if path != new_path:
2178 path = new_path
2179 each['path'] = path
2180 path_list.append(path)
2181 else:
2182 del each['path']
2183 if each['order'] == each['offset']:
2184 del each['order']
2185 del each['offset']
2186
2187 # value is just used to indicate display type
2188 value = each['value']
2189 if value.startswith('0x'):
2190 hex_len = ((each['length'] + 7) // 8) * 2
2191 if len(value) == hex_len:
2192 value = 'x%d' % hex_len
2193 else:
2194 value = 'x'
2195 each['value'] = value
2196 elif value and value[0] in ['"', "'", '{']:
2197 each['value'] = value[0]
2198 else:
2199 del each['value']
2200
2201 fo.write(repr(cfgs))
2202 fo.close()
2203 return 0
2204
2205 if dlt_file:
2206 gen_cfg_data.override_default_value(dlt_file)
2207
2208 gen_cfg_data.detect_fsp()
2209
2210 if command == "GENBIN":
2211 if len(file_list) == 3:
2212 old_data = gen_cfg_data.generate_binary_array()
2213 fi = open(file_list[2], 'rb')
2214 new_data = bytearray(fi.read())
2215 fi.close()
2216 if len(new_data) != len(old_data):
2217 raise Exception("Binary file '%s' length does not match, \
2218 ignored !" % file_list[2])
2219 else:
2220 gen_cfg_data.load_default_from_bin(new_data)
2221 gen_cfg_data.override_default_value(dlt_file)
2222
2223 gen_cfg_data.generate_binary(out_file, yml_scope)
2224
2225 elif command == "GENDLT":
2226 full = True if 'FULL' in gen_cfg_data._macro_dict else False
2227 gen_cfg_data.generate_delta_file(out_file, cfg_bin_file,
2228 cfg_bin_file2, full)
2229
2230 elif command == "GENHDR":
2231 out_files = out_file.split(';')
2232 brd_out_file = out_files[0].strip()
2233 if len(out_files) > 1:
2234 com_out_file = out_files[1].strip()
2235 else:
2236 com_out_file = ''
2237 gen_cfg_data.create_header_file(brd_out_file, com_out_file, yml_scope)
2238
2239 elif command == "GENINC":
2240 gen_cfg_data.generate_data_inc_file(out_file)
2241
2242 elif command == "DEBUG":
2243 gen_cfg_data.print_cfgs()
2244
2245 else:
2246 raise Exception("Unsuported command '%s' !" % command)
2247
2248 return 0
2249
2250
2251 if __name__ == '__main__':
2252 sys.exit(main())