]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
IntelFsp2Pkg: Add search function for Config Editor
[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.bin_offset = []
587 self.binseg_dict = {}
588 self.initialize()
589
590 def initialize(self):
591 self._old_bin = None
592 self._cfg_tree = {}
593 self._tmp_tree = {}
594 self._cfg_list = []
595 self._cfg_page = {'root': {'title': '', 'child': []}}
596 self._cur_page = ''
597 self._var_dict = {}
598 self._def_dict = {}
599 self._yaml_path = ''
600
601 @staticmethod
602 def deep_convert_dict(layer):
603 # convert OrderedDict to list + dict
604 new_list = layer
605 if isinstance(layer, OrderedDict):
606 new_list = list(layer.items())
607 for idx, pair in enumerate(new_list):
608 new_node = CGenYamlCfg.deep_convert_dict(pair[1])
609 new_list[idx] = dict({pair[0]: new_node})
610 return new_list
611
612 @staticmethod
613 def deep_convert_list(layer):
614 if isinstance(layer, list):
615 od = OrderedDict({})
616 for each in layer:
617 if isinstance(each, dict):
618 key = next(iter(each))
619 od[key] = CGenYamlCfg.deep_convert_list(each[key])
620 return od
621 else:
622 return layer
623
624 @staticmethod
625 def expand_include_files(file_path, cur_dir=''):
626 if cur_dir == '':
627 cur_dir = os.path.dirname(file_path)
628 file_path = os.path.basename(file_path)
629
630 input_file_path = os.path.join(cur_dir, file_path)
631 file = open(input_file_path, "r")
632 lines = file.readlines()
633 file.close()
634 new_lines = []
635 for line_num, line in enumerate(lines):
636 match = re.match("^!include\\s*(.+)?$", line.strip())
637 if match:
638 inc_path = match.group(1)
639 tmp_path = os.path.join(cur_dir, inc_path)
640 org_path = tmp_path
641 if not os.path.exists(tmp_path):
642 cur_dir = os.path.join(os.path.dirname
643 (os.path.realpath(__file__)
644 ), "..", "..")
645 tmp_path = os.path.join(cur_dir, inc_path)
646 if not os.path.exists(tmp_path):
647 raise Exception("ERROR: Cannot open include\
648 file '%s'." % org_path)
649 else:
650 new_lines.append(('# Included from file: %s\n' % inc_path,
651 tmp_path, 0))
652 new_lines.append(('# %s\n' % ('=' * 80), tmp_path, 0))
653 new_lines.extend(CGenYamlCfg.expand_include_files
654 (inc_path, cur_dir))
655 else:
656 new_lines.append((line, input_file_path, line_num))
657
658 return new_lines
659
660 @staticmethod
661 def format_struct_field_name(input, count=0):
662 name = ''
663 cap = True
664 if '_' in input:
665 input = input.lower()
666 for each in input:
667 if each == '_':
668 cap = True
669 continue
670 elif cap:
671 each = each.upper()
672 cap = False
673 name = name + each
674
675 if count > 1:
676 name = '%s[%d]' % (name, count)
677
678 return name
679
680 def get_mode(self):
681 return self._mode
682
683 def set_mode(self, mode):
684 self._mode = mode
685
686 def get_last_error(self):
687 return ''
688
689 def get_variable(self, var, attr='value'):
690 if var in self._var_dict:
691 var = self._var_dict[var]
692 return var
693
694 item = self.locate_cfg_item(var, False)
695 if item is None:
696 raise ValueError("Cannot find variable '%s' !" % var)
697
698 if item:
699 if 'indx' in item:
700 item = self.get_item_by_index(item['indx'])
701 if attr == 'offset':
702 var = item['offset']
703 elif attr == 'length':
704 var = item['length']
705 elif attr == 'value':
706 var = self.get_cfg_item_value(item)
707 else:
708 raise ValueError("Unsupported variable attribute '%s' !" %
709 attr)
710 return var
711
712 def eval(self, expr):
713 def _handler(pattern):
714 if pattern.group(1):
715 target = 1
716 else:
717 target = 2
718 result = self.get_variable(pattern.group(target))
719 if result is None:
720 raise ValueError('Unknown variable $(%s) !' %
721 pattern.group(target))
722 return hex(result)
723
724 expr_eval = ExpressionEval()
725 if '$' in expr:
726 # replace known variable first
727 expr = re.sub(r'\$\(([_a-zA-Z][\w\.]*)\)|\$([_a-zA-Z][\w\.]*)',
728 _handler, expr)
729 return expr_eval.eval(expr, self.get_variable)
730
731 def parse_macros(self, macro_def_str):
732 # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']
733 self._macro_dict = {}
734 is_expression = False
735 for macro in macro_def_str:
736 if macro.startswith('-D'):
737 is_expression = True
738 if len(macro) > 2:
739 macro = macro[2:]
740 else:
741 continue
742 if is_expression:
743 is_expression = False
744 match = re.match("(\\w+)=(.+)", macro)
745 if match:
746 self._macro_dict[match.group(1)] = match.group(2)
747 else:
748 match = re.match("(\\w+)", macro)
749 if match:
750 self._macro_dict[match.group(1)] = ''
751 if len(self._macro_dict) == 0:
752 error = 1
753 else:
754 error = 0
755 if self._debug:
756 print("INFO : Macro dictionary:")
757 for each in self._macro_dict:
758 print(" $(%s) = [ %s ]"
759 % (each, self._macro_dict[each]))
760 return error
761
762 def get_cfg_list(self, page_id=None):
763 if page_id is None:
764 # return full list
765 return self._cfg_list
766 else:
767 # build a new list for items under a page ID
768 cfgs = [i for i in self._cfg_list if i['cname'] and
769 (i['page'] == page_id)]
770 return cfgs
771
772 def get_cfg_page(self):
773 return self._cfg_page
774
775 def get_cfg_item_length(self, item):
776 return item['length']
777
778 def get_cfg_item_value(self, item, array=False):
779 value_str = item['value']
780 length = item['length']
781 return self.get_value(value_str, length, array)
782
783 def format_value_to_str(self, value, bit_length, old_value=''):
784 # value is always int
785 length = (bit_length + 7) // 8
786 fmt = ''
787 if old_value.startswith('0x'):
788 fmt = '0x'
789 elif old_value and (old_value[0] in ['"', "'", '{']):
790 fmt = old_value[0]
791 else:
792 fmt = ''
793
794 bvalue = value_to_bytearray(value, length)
795 if fmt in ['"', "'"]:
796 svalue = bvalue.rstrip(b'\x00').decode()
797 value_str = fmt + svalue + fmt
798 elif fmt == "{":
799 value_str = '{ ' + ', '.join(['0x%02x' % i for i in bvalue]) + ' }'
800 elif fmt == '0x':
801 hex_len = length * 2
802 if len(old_value) == hex_len + 2:
803 fstr = '0x%%0%dx' % hex_len
804 else:
805 fstr = '0x%x'
806 value_str = fstr % value
807 else:
808 if length <= 2:
809 value_str = '%d' % value
810 elif length <= 8:
811 value_str = '0x%x' % value
812 else:
813 value_str = '{ ' + ', '.join(['0x%02x' % i for i in
814 bvalue]) + ' }'
815 return value_str
816
817 def reformat_value_str(self, value_str, bit_length, old_value=None):
818 value = self.parse_value(value_str, bit_length, False)
819 if old_value is None:
820 old_value = value_str
821 new_value = self.format_value_to_str(value, bit_length, old_value)
822 return new_value
823
824 def get_value(self, value_str, bit_length, array=True):
825 value_str = value_str.strip()
826 if value_str[0] == "'" and value_str[-1] == "'" or \
827 value_str[0] == '"' and value_str[-1] == '"':
828 value_str = value_str[1:-1]
829 bvalue = bytearray(value_str.encode())
830 if len(bvalue) == 0:
831 bvalue = bytearray(b'\x00')
832 if array:
833 return bvalue
834 else:
835 return bytes_to_value(bvalue)
836 else:
837 if value_str[0] in '{':
838 value_str = value_str[1:-1].strip()
839 value = 0
840 for each in value_str.split(',')[::-1]:
841 each = each.strip()
842 value = (value << 8) | int(each, 0)
843 if array:
844 length = (bit_length + 7) // 8
845 return value_to_bytearray(value, length)
846 else:
847 return value
848
849 def parse_value(self, value_str, bit_length, array=True):
850 length = (bit_length + 7) // 8
851 if check_quote(value_str):
852 value_str = bytes_to_bracket_str(value_str[1:-1].encode())
853 elif (',' in value_str) and (value_str[0] != '{'):
854 value_str = '{ %s }' % value_str
855 if value_str[0] == '{':
856 result = expand_file_value(self._yaml_path, value_str)
857 if len(result) == 0:
858 bin_list = value_str[1:-1].split(',')
859 value = 0
860 bit_len = 0
861 unit_len = 1
862 for idx, element in enumerate(bin_list):
863 each = element.strip()
864 if len(each) == 0:
865 continue
866
867 in_bit_field = False
868 if each[0] in "'" + '"':
869 each_value = bytearray(each[1:-1], 'utf-8')
870 elif ':' in each:
871 match = re.match("^(.+):(\\d+)([b|B|W|D|Q])$", each)
872 if match is None:
873 raise SystemExit("Exception: Invald value\
874 list format '%s' !" % each)
875 if match.group(1) == '0' and match.group(2) == '0':
876 unit_len = CGenYamlCfg.bits_width[match.group(3)
877 ] // 8
878 cur_bit_len = int(match.group(2)
879 ) * CGenYamlCfg.bits_width[
880 match.group(3)]
881 value += ((self.eval(match.group(1)) & (
882 1 << cur_bit_len) - 1)) << bit_len
883 bit_len += cur_bit_len
884 each_value = bytearray()
885 if idx + 1 < len(bin_list):
886 in_bit_field = True
887 else:
888 try:
889 each_value = value_to_bytearray(
890 self.eval(each.strip()), unit_len)
891 except Exception:
892 raise SystemExit("Exception: Value %d cannot \
893 fit into %s bytes !" % (each, unit_len))
894
895 if not in_bit_field:
896 if bit_len > 0:
897 if bit_len % 8 != 0:
898 raise SystemExit("Exception: Invalid bit \
899 field alignment '%s' !" % value_str)
900 result.extend(value_to_bytes(value, bit_len // 8))
901 value = 0
902 bit_len = 0
903
904 result.extend(each_value)
905
906 elif check_quote(value_str):
907 result = bytearray(value_str[1:-1], 'utf-8') # Excluding quotes
908 else:
909 result = value_to_bytearray(self.eval(value_str), length)
910
911 if len(result) < length:
912 result.extend(b'\x00' * (length - len(result)))
913 elif len(result) > length:
914 raise SystemExit("Exception: Value '%s' is too big to fit \
915 into %d bytes !" % (value_str, length))
916
917 if array:
918 return result
919 else:
920 return bytes_to_value(result)
921
922 return result
923
924 def get_cfg_item_options(self, item):
925 tmp_list = []
926 if item['type'] == "Combo":
927 if item['option'] in CGenYamlCfg.builtin_option:
928 for op_val, op_str in CGenYamlCfg.builtin_option[item['option'
929 ]]:
930 tmp_list.append((op_val, op_str))
931 else:
932 opt_list = item['option'].split(',')
933 for option in opt_list:
934 option = option.strip()
935 try:
936 (op_val, op_str) = option.split(':')
937 except Exception:
938 raise SystemExit("Exception: Invalide \
939 option format '%s' !" % option)
940 tmp_list.append((op_val, op_str))
941 return tmp_list
942
943 def get_page_title(self, page_id, top=None):
944 if top is None:
945 top = self.get_cfg_page()['root']
946 for node in top['child']:
947 page_key = next(iter(node))
948 if page_id == page_key:
949 return node[page_key]['title']
950 else:
951 result = self.get_page_title(page_id, node[page_key])
952 if result is not None:
953 return result
954 return None
955
956 def print_pages(self, top=None, level=0):
957 if top is None:
958 top = self.get_cfg_page()['root']
959 for node in top['child']:
960 page_id = next(iter(node))
961 print('%s%s: %s' % (' ' * level, page_id, node[page_id]['title']))
962 level += 1
963 self.print_pages(node[page_id], level)
964 level -= 1
965
966 def get_item_by_index(self, index):
967 return self._cfg_list[index]
968
969 def get_item_by_path(self, path):
970 node = self.locate_cfg_item(path)
971 if node:
972 return self.get_item_by_index(node['indx'])
973 else:
974 return None
975
976 def locate_cfg_path(self, item):
977 def _locate_cfg_path(root, level=0):
978 # config structure
979 if item is root:
980 return path
981 for key in root:
982 if type(root[key]) is OrderedDict:
983 level += 1
984 path.append(key)
985 ret = _locate_cfg_path(root[key], level)
986 if ret:
987 return ret
988 path.pop()
989 return None
990 path = []
991 return _locate_cfg_path(self._cfg_tree)
992
993 def locate_cfg_item(self, path, allow_exp=True):
994 def _locate_cfg_item(root, path, level=0):
995 if len(path) == level:
996 return root
997 next_root = root.get(path[level], None)
998 if next_root is None:
999 if allow_exp:
1000 raise Exception('Not a valid CFG config option path: %s' %
1001 '.'.join(path[:level+1]))
1002 else:
1003 return None
1004 return _locate_cfg_item(next_root, path, level + 1)
1005
1006 path_nodes = path.split('.')
1007 return _locate_cfg_item(self._cfg_tree, path_nodes)
1008
1009 def traverse_cfg_tree(self, handler, top=None):
1010 def _traverse_cfg_tree(root, level=0):
1011 # config structure
1012 for key in root:
1013 if type(root[key]) is OrderedDict:
1014 level += 1
1015 handler(key, root[key], level)
1016 _traverse_cfg_tree(root[key], level)
1017 level -= 1
1018
1019 if top is None:
1020 top = self._cfg_tree
1021 _traverse_cfg_tree(top)
1022
1023 def print_cfgs(self, root=None, short=True, print_level=256):
1024 def _print_cfgs(name, cfgs, level):
1025
1026 if 'indx' in cfgs:
1027 act_cfg = self.get_item_by_index(cfgs['indx'])
1028 else:
1029 offset = 0
1030 length = 0
1031 value = ''
1032 if CGenYamlCfg.STRUCT in cfgs:
1033 cfg = cfgs[CGenYamlCfg.STRUCT]
1034 offset = int(cfg['offset'])
1035 length = int(cfg['length'])
1036 if 'value' in cfg:
1037 value = cfg['value']
1038 if length == 0:
1039 return
1040 act_cfg = dict({'value': value, 'offset': offset,
1041 'length': length})
1042 value = act_cfg['value']
1043 bit_len = act_cfg['length']
1044 offset = (act_cfg['offset'] + 7) // 8
1045 if value != '':
1046 try:
1047 value = self.reformat_value_str(act_cfg['value'],
1048 act_cfg['length'])
1049 except Exception:
1050 value = act_cfg['value']
1051 length = bit_len // 8
1052 bit_len = '(%db)' % bit_len if bit_len % 8 else '' * 4
1053 if level <= print_level:
1054 if short and len(value) > 40:
1055 value = '%s ... %s' % (value[:20], value[-20:])
1056 print('%04X:%04X%-6s %s%s : %s' % (offset, length, bit_len,
1057 ' ' * level, name, value))
1058
1059 self.traverse_cfg_tree(_print_cfgs)
1060
1061 def build_var_dict(self):
1062 def _build_var_dict(name, cfgs, level):
1063 if level <= 2:
1064 if CGenYamlCfg.STRUCT in cfgs:
1065 struct_info = cfgs[CGenYamlCfg.STRUCT]
1066 self._var_dict['_LENGTH_%s_' % name] = struct_info[
1067 'length'] // 8
1068 self._var_dict['_OFFSET_%s_' % name] = struct_info[
1069 'offset'] // 8
1070
1071 self._var_dict = {}
1072 self.traverse_cfg_tree(_build_var_dict)
1073 self._var_dict['_LENGTH_'] = self._cfg_tree[CGenYamlCfg.STRUCT][
1074 'length'] // 8
1075 return 0
1076
1077 def add_cfg_page(self, child, parent, title=''):
1078 def _add_cfg_page(cfg_page, child, parent):
1079 key = next(iter(cfg_page))
1080 if parent == key:
1081 cfg_page[key]['child'].append({child: {'title': title,
1082 'child': []}})
1083 return True
1084 else:
1085 result = False
1086 for each in cfg_page[key]['child']:
1087 if _add_cfg_page(each, child, parent):
1088 result = True
1089 break
1090 return result
1091
1092 return _add_cfg_page(self._cfg_page, child, parent)
1093
1094 def set_cur_page(self, page_str):
1095 if not page_str:
1096 return
1097
1098 if ',' in page_str:
1099 page_list = page_str.split(',')
1100 else:
1101 page_list = [page_str]
1102 for page_str in page_list:
1103 parts = page_str.split(':')
1104 if len(parts) in [1, 3]:
1105 page = parts[0].strip()
1106 if len(parts) == 3:
1107 # it is a new page definition, add it into tree
1108 parent = parts[1] if parts[1] else 'root'
1109 parent = parent.strip()
1110 if parts[2][0] == '"' and parts[2][-1] == '"':
1111 parts[2] = parts[2][1:-1]
1112
1113 if not self.add_cfg_page(page, parent, parts[2]):
1114 raise SystemExit("Error: Cannot find parent page \
1115 '%s'!" % parent)
1116 else:
1117 raise SystemExit("Error: Invalid page format '%s' !"
1118 % page_str)
1119 self._cur_page = page
1120
1121 def extend_variable(self, line):
1122 # replace all variables
1123 if line == '':
1124 return line
1125 loop = 2
1126 while loop > 0:
1127 line_after = DefTemplate(line).safe_substitute(self._def_dict)
1128 if line == line_after:
1129 break
1130 loop -= 1
1131 line = line_after
1132 return line_after
1133
1134 def reformat_number_per_type(self, itype, value):
1135 if check_quote(value) or value.startswith('{'):
1136 return value
1137 parts = itype.split(',')
1138 if len(parts) > 3 and parts[0] == 'EditNum':
1139 num_fmt = parts[1].strip()
1140 else:
1141 num_fmt = ''
1142 if num_fmt == 'HEX' and not value.startswith('0x'):
1143 value = '0x%X' % int(value, 10)
1144 elif num_fmt == 'DEC' and value.startswith('0x'):
1145 value = '%d' % int(value, 16)
1146 return value
1147
1148 def add_cfg_item(self, name, item, offset, path):
1149
1150 self.set_cur_page(item.get('page', ''))
1151
1152 if name[0] == '$':
1153 # skip all virtual node
1154 return 0
1155
1156 if not set(item).issubset(CGenYamlCfg.keyword_set):
1157 for each in list(item):
1158 if each not in CGenYamlCfg.keyword_set:
1159 raise Exception("Invalid attribute '%s' for '%s'!" %
1160 (each, '.'.join(path)))
1161
1162 length = item.get('length', 0)
1163 if type(length) is str:
1164 match = re.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)\\s*$", length)
1165 if match:
1166 unit_len = CGenYamlCfg.bits_width[match.group(2)]
1167 length = int(match.group(1), 10) * unit_len
1168 else:
1169 try:
1170 length = int(length, 0) * 8
1171 except Exception:
1172 raise Exception("Invalid length field '%s' for '%s' !" %
1173 (length, '.'.join(path)))
1174
1175 if offset % 8 > 0:
1176 raise Exception("Invalid alignment for field '%s' for \
1177 '%s' !" % (name, '.'.join(path)))
1178 else:
1179 # define is length in bytes
1180 length = length * 8
1181
1182 if not name.isidentifier():
1183 raise Exception("Invalid config name '%s' for '%s' !" %
1184 (name, '.'.join(path)))
1185
1186 itype = str(item.get('type', 'Reserved'))
1187 value = str(item.get('value', ''))
1188 if value:
1189 if not (check_quote(value) or value.startswith('{')):
1190 if ',' in value:
1191 value = '{ %s }' % value
1192 else:
1193 value = self.reformat_number_per_type(itype, value)
1194
1195 help = str(item.get('help', ''))
1196 if '\n' in help:
1197 help = ' '.join([i.strip() for i in help.splitlines()])
1198
1199 option = str(item.get('option', ''))
1200 if '\n' in option:
1201 option = ' '.join([i.strip() for i in option.splitlines()])
1202
1203 # extend variables for value and condition
1204 condition = str(item.get('condition', ''))
1205 if condition:
1206 condition = self.extend_variable(condition)
1207 value = self.extend_variable(value)
1208
1209 order = str(item.get('order', ''))
1210 if order:
1211 if '.' in order:
1212 (major, minor) = order.split('.')
1213 order = int(major, 16)
1214 else:
1215 order = int(order, 16)
1216 else:
1217 order = offset
1218
1219 cfg_item = dict()
1220 cfg_item['length'] = length
1221 cfg_item['offset'] = offset
1222 cfg_item['value'] = value
1223 cfg_item['type'] = itype
1224 cfg_item['cname'] = str(name)
1225 cfg_item['name'] = str(item.get('name', ''))
1226 cfg_item['help'] = help
1227 cfg_item['option'] = option
1228 cfg_item['page'] = self._cur_page
1229 cfg_item['order'] = order
1230 cfg_item['path'] = '.'.join(path)
1231 cfg_item['condition'] = condition
1232 if 'struct' in item:
1233 cfg_item['struct'] = item['struct']
1234 self._cfg_list.append(cfg_item)
1235
1236 item['indx'] = len(self._cfg_list) - 1
1237
1238 # remove used info for reducing pkl size
1239 item.pop('option', None)
1240 item.pop('condition', None)
1241 item.pop('help', None)
1242 item.pop('name', None)
1243 item.pop('page', None)
1244
1245 return length
1246
1247 def build_cfg_list(self, cfg_name='', top=None, path=[],
1248 info={'offset': 0}):
1249 if top is None:
1250 top = self._cfg_tree
1251 info.clear()
1252 info = {'offset': 0}
1253
1254 start = info['offset']
1255 is_leaf = True
1256 for key in top:
1257 path.append(key)
1258 if type(top[key]) is OrderedDict:
1259 is_leaf = False
1260 self.build_cfg_list(key, top[key], path, info)
1261 path.pop()
1262
1263 if is_leaf:
1264 length = self.add_cfg_item(cfg_name, top, info['offset'], path)
1265 info['offset'] += length
1266 elif cfg_name == '' or (cfg_name and cfg_name[0] != '$'):
1267 # check first element for struct
1268 first = next(iter(top))
1269 struct_str = CGenYamlCfg.STRUCT
1270 if first != struct_str:
1271 struct_node = OrderedDict({})
1272 top[struct_str] = struct_node
1273 top.move_to_end(struct_str, False)
1274 else:
1275 struct_node = top[struct_str]
1276 struct_node['offset'] = start
1277 struct_node['length'] = info['offset'] - start
1278 if struct_node['length'] % 8 != 0:
1279 raise SystemExit("Error: Bits length not aligned for %s !" %
1280 str(path))
1281
1282 def get_field_value(self, top=None):
1283 def _get_field_value(name, cfgs, level):
1284 if 'indx' in cfgs:
1285 act_cfg = self.get_item_by_index(cfgs['indx'])
1286 if act_cfg['length'] == 0:
1287 return
1288 value = self.get_value(act_cfg['value'], act_cfg['length'],
1289 False)
1290 set_bits_to_bytes(result, act_cfg['offset'] -
1291 struct_info['offset'], act_cfg['length'],
1292 value)
1293
1294 if top is None:
1295 top = self._cfg_tree
1296 struct_info = top[CGenYamlCfg.STRUCT]
1297 result = bytearray((struct_info['length'] + 7) // 8)
1298 self.traverse_cfg_tree(_get_field_value, top)
1299 return result
1300
1301 def set_field_value(self, top, value_bytes, force=False):
1302 def _set_field_value(name, cfgs, level):
1303 if 'indx' not in cfgs:
1304 return
1305 act_cfg = self.get_item_by_index(cfgs['indx'])
1306 actual_offset = act_cfg['offset'] - struct_info['offset']
1307 set_value = True
1308 for each in self.bin_offset:
1309 if actual_offset in range(each[0], (each[0] + each[2]) * 8):
1310 if each[1] < 0:
1311 set_value = False
1312 if set_value and force or act_cfg['value'] == '':
1313 value = get_bits_from_bytes(full_bytes,
1314 actual_offset,
1315 act_cfg['length'])
1316 act_val = act_cfg['value']
1317 if act_val == '':
1318 act_val = '%d' % value
1319 act_val = self.reformat_number_per_type(act_cfg
1320 ['type'],
1321 act_val)
1322 act_cfg['value'] = self.format_value_to_str(
1323 value, act_cfg['length'], act_val)
1324
1325 if 'indx' in top:
1326 # it is config option
1327 value = bytes_to_value(value_bytes)
1328 act_cfg = self.get_item_by_index(top['indx'])
1329 act_cfg['value'] = self.format_value_to_str(
1330 value, act_cfg['length'], act_cfg['value'])
1331 else:
1332 # it is structure
1333 struct_info = top[CGenYamlCfg.STRUCT]
1334 length = struct_info['length'] // 8
1335 full_bytes = bytearray(value_bytes[:length])
1336 if len(full_bytes) < length:
1337 full_bytes.extend(bytearray(length - len(value_bytes)))
1338 self.traverse_cfg_tree(_set_field_value, top)
1339
1340 def update_def_value(self):
1341 def _update_def_value(name, cfgs, level):
1342 if 'indx' in cfgs:
1343 act_cfg = self.get_item_by_index(cfgs['indx'])
1344 if act_cfg['value'] != '' and act_cfg['length'] > 0:
1345 try:
1346 act_cfg['value'] = self.reformat_value_str(
1347 act_cfg['value'], act_cfg['length'])
1348 except Exception:
1349 raise Exception("Invalid value expression '%s' \
1350 for '%s' !" % (act_cfg['value'], act_cfg['path']))
1351 else:
1352 if CGenYamlCfg.STRUCT in cfgs and 'value' in \
1353 cfgs[CGenYamlCfg.STRUCT]:
1354 curr = cfgs[CGenYamlCfg.STRUCT]
1355 value_bytes = self.get_value(curr['value'],
1356 curr['length'], True)
1357 self.set_field_value(cfgs, value_bytes)
1358
1359 self.traverse_cfg_tree(_update_def_value, self._cfg_tree)
1360
1361 def evaluate_condition(self, item):
1362 expr = item['condition']
1363 result = self.parse_value(expr, 1, False)
1364 return result
1365
1366 def detect_fsp(self):
1367 cfg_segs = self.get_cfg_segment()
1368 if len(cfg_segs) == 3:
1369 fsp = True
1370 for idx, seg in enumerate(cfg_segs):
1371 if not seg[0].endswith('UPD_%s' % 'TMS'[idx]):
1372 fsp = False
1373 break
1374 else:
1375 fsp = False
1376 if fsp:
1377 self.set_mode('FSP')
1378 return fsp
1379
1380 def get_cfg_segment(self):
1381 def _get_cfg_segment(name, cfgs, level):
1382 if 'indx' not in cfgs:
1383 if name.startswith('$ACTION_'):
1384 if 'find' in cfgs:
1385 find[0] = cfgs['find']
1386 else:
1387 if find[0]:
1388 act_cfg = self.get_item_by_index(cfgs['indx'])
1389 segments.append([find[0], act_cfg['offset'] // 8, 0])
1390 find[0] = ''
1391 return
1392
1393 find = ['']
1394 segments = []
1395 self.traverse_cfg_tree(_get_cfg_segment, self._cfg_tree)
1396 cfg_len = self._cfg_tree[CGenYamlCfg.STRUCT]['length'] // 8
1397 if len(segments) == 0:
1398 segments.append(['', 0, cfg_len])
1399
1400 segments.append(['', cfg_len, 0])
1401 cfg_segs = []
1402 for idx, each in enumerate(segments[:-1]):
1403 cfg_segs.append((each[0], each[1],
1404 segments[idx+1][1] - each[1]))
1405
1406 return cfg_segs
1407
1408 def get_bin_segment(self, bin_data):
1409 cfg_segs = self.get_cfg_segment()
1410 bin_segs = []
1411 for seg in cfg_segs:
1412 key = seg[0].encode()
1413 if key == 0:
1414 bin_segs.append([seg[0], 0, len(bin_data)])
1415 break
1416 pos = bin_data.find(key)
1417 if pos >= 0:
1418 # ensure no other match for the key
1419 next_pos = bin_data.find(key, pos + len(seg[0]))
1420 if next_pos >= 0:
1421 if key == b'$SKLFSP$' or key == b'$BSWFSP$':
1422 string = ('Warning: Multiple matches for %s in '
1423 'binary!\n\nA workaround applied to such '
1424 'FSP 1.x binary to use second'
1425 ' match instead of first match!' % key)
1426 messagebox.showwarning('Warning!', string)
1427 pos = next_pos
1428 else:
1429 print("Warning: Multiple matches for '%s' "
1430 "in binary, the 1st instance will be used !"
1431 % seg[0])
1432 bin_segs.append([seg[0], pos, seg[2]])
1433 self.binseg_dict[seg[0]] = pos
1434 else:
1435 bin_segs.append([seg[0], -1, seg[2]])
1436 self.binseg_dict[seg[0]] = -1
1437 continue
1438
1439 return bin_segs
1440
1441 def extract_cfg_from_bin(self, bin_data):
1442 # get cfg bin length
1443 cfg_bins = bytearray()
1444 bin_segs = self.get_bin_segment(bin_data)
1445 Dummy_offset = 0
1446 for each in bin_segs:
1447 if each[1] != -1:
1448 self.bin_offset.append([Dummy_offset, each[1], each[2]])
1449 cfg_bins.extend(bin_data[each[1]:each[1] + each[2]])
1450 else:
1451 string = each[0] + ' is not availabe.'
1452 messagebox.showinfo('', string)
1453 self.bin_offset.append([Dummy_offset, each[1], each[2]])
1454 cfg_bins.extend(bytearray(each[2]))
1455 Dummy_offset += each[2]
1456 return cfg_bins
1457
1458 def save_current_to_bin(self):
1459 cfg_bins = self.generate_binary_array()
1460 if self._old_bin is None:
1461 return cfg_bins
1462
1463 bin_data = bytearray(self._old_bin)
1464 bin_segs = self.get_bin_segment(self._old_bin)
1465 cfg_off = 0
1466 for each in bin_segs:
1467 length = each[2]
1468 if each[1] != -1:
1469 bin_data[each[1]:each[1] + length] = cfg_bins[cfg_off:
1470 cfg_off
1471 + length]
1472 cfg_off += length
1473 else:
1474 cfg_off += length
1475
1476 print('Patched the loaded binary successfully !')
1477 return bin_data
1478
1479 def load_default_from_bin(self, bin_data):
1480 self._old_bin = bin_data
1481 cfg_bins = self.extract_cfg_from_bin(bin_data)
1482 self.set_field_value(self._cfg_tree, cfg_bins, True)
1483 return cfg_bins
1484
1485 def generate_binary_array(self, path=''):
1486 if path == '':
1487 top = None
1488 else:
1489 top = self.locate_cfg_item(path)
1490 if not top:
1491 raise Exception("Invalid configuration path '%s' !"
1492 % path)
1493
1494 return self.get_field_value(top)
1495
1496 def generate_binary(self, bin_file_name, path=''):
1497 bin_file = open(bin_file_name, "wb")
1498 bin_file.write(self.generate_binary_array(path))
1499 bin_file.close()
1500 return 0
1501
1502 def write_delta_file(self, out_file, platform_id, out_lines):
1503 dlt_fd = open(out_file, "w")
1504 dlt_fd.write("%s\n" % get_copyright_header('dlt', True))
1505 if platform_id is not None:
1506 dlt_fd.write('#\n')
1507 dlt_fd.write('# Delta configuration values for '
1508 'platform ID 0x%04X\n'
1509 % platform_id)
1510 dlt_fd.write('#\n\n')
1511 for line in out_lines:
1512 dlt_fd.write('%s\n' % line)
1513 dlt_fd.close()
1514
1515 def override_default_value(self, dlt_file):
1516 error = 0
1517 dlt_lines = CGenYamlCfg.expand_include_files(dlt_file)
1518
1519 platform_id = None
1520 for line, file_path, line_num in dlt_lines:
1521 line = line.strip()
1522 if not line or line.startswith('#'):
1523 continue
1524 match = re.match("\\s*([\\w\\.]+)\\s*\\|\\s*(.+)", line)
1525 if not match:
1526 raise Exception("Unrecognized line '%s' "
1527 "(File:'%s' Line:%d) !"
1528 % (line, file_path, line_num + 1))
1529
1530 path = match.group(1)
1531 value_str = match.group(2)
1532 top = self.locate_cfg_item(path)
1533 if not top:
1534 raise Exception(
1535 "Invalid configuration '%s' (File:'%s' Line:%d) !" %
1536 (path, file_path, line_num + 1))
1537
1538 if 'indx' in top:
1539 act_cfg = self.get_item_by_index(top['indx'])
1540 bit_len = act_cfg['length']
1541 else:
1542 struct_info = top[CGenYamlCfg.STRUCT]
1543 bit_len = struct_info['length']
1544
1545 value_bytes = self.parse_value(value_str, bit_len)
1546 self.set_field_value(top, value_bytes, True)
1547
1548 if path == 'PLATFORMID_CFG_DATA.PlatformId':
1549 platform_id = value_str
1550
1551 if platform_id is None:
1552 raise Exception(
1553 "PLATFORMID_CFG_DATA.PlatformId is missing "
1554 "in file '%s' !" %
1555 (dlt_file))
1556
1557 return error
1558
1559 def generate_delta_file_from_bin(self, delta_file, old_data,
1560 new_data, full=False):
1561 new_data = self.load_default_from_bin(new_data)
1562 lines = []
1563 platform_id = None
1564 def_platform_id = 0
1565
1566 for item in self._cfg_list:
1567 if not full and (item['type'] in ['Reserved']):
1568 continue
1569 old_val = get_bits_from_bytes(old_data, item['offset'],
1570 item['length'])
1571 new_val = get_bits_from_bytes(new_data, item['offset'],
1572 item['length'])
1573
1574 full_name = item['path']
1575 if 'PLATFORMID_CFG_DATA.PlatformId' == full_name:
1576 def_platform_id = old_val
1577 if new_val != old_val or full:
1578 val_str = self.reformat_value_str(item['value'],
1579 item['length'])
1580 text = '%-40s | %s' % (full_name, val_str)
1581 lines.append(text)
1582
1583 if self.get_mode() != 'FSP':
1584 if platform_id is None or def_platform_id == platform_id:
1585 platform_id = def_platform_id
1586 print("WARNING: 'PlatformId' configuration is "
1587 "same as default %d!" % platform_id)
1588
1589 lines.insert(0, '%-40s | %s\n\n' %
1590 ('PLATFORMID_CFG_DATA.PlatformId',
1591 '0x%04X' % platform_id))
1592 else:
1593 platform_id = None
1594
1595 self.write_delta_file(delta_file, platform_id, lines)
1596
1597 return 0
1598
1599 def generate_delta_file(self, delta_file, bin_file, bin_file2, full=False):
1600 fd = open(bin_file, 'rb')
1601 new_data = self.extract_cfg_from_bin(bytearray(fd.read()))
1602 fd.close()
1603
1604 if bin_file2 == '':
1605 old_data = self.generate_binary_array()
1606 else:
1607 old_data = new_data
1608 fd = open(bin_file2, 'rb')
1609 new_data = self.extract_cfg_from_bin(bytearray(fd.read()))
1610 fd.close()
1611
1612 return self.generate_delta_file_from_bin(delta_file,
1613 old_data, new_data, full)
1614
1615 def prepare_marshal(self, is_save):
1616 if is_save:
1617 # Ordered dict is not marshallable, convert to list
1618 self._cfg_tree = CGenYamlCfg.deep_convert_dict(self._cfg_tree)
1619 else:
1620 # Revert it back
1621 self._cfg_tree = CGenYamlCfg.deep_convert_list(self._cfg_tree)
1622
1623 def generate_yml_file(self, in_file, out_file):
1624 cfg_yaml = CFG_YAML()
1625 text = cfg_yaml.expand_yaml(in_file)
1626 yml_fd = open(out_file, "w")
1627 yml_fd.write(text)
1628 yml_fd.close()
1629 return 0
1630
1631 def write_cfg_header_file(self, hdr_file_name, tag_mode,
1632 tag_dict, struct_list):
1633 lines = []
1634 lines.append('\n\n')
1635 if self.get_mode() == 'FSP':
1636 lines.append('#include <FspUpd.h>\n')
1637
1638 tag_mode = tag_mode & 0x7F
1639 tag_list = sorted(list(tag_dict.items()), key=lambda x: x[1])
1640 for tagname, tagval in tag_list:
1641 if (tag_mode == 0 and tagval >= 0x100) or \
1642 (tag_mode == 1 and tagval < 0x100):
1643 continue
1644 lines.append('#define %-30s 0x%03X\n' % (
1645 'CDATA_%s_TAG' % tagname[:-9], tagval))
1646 lines.append('\n\n')
1647
1648 name_dict = {}
1649 new_dict = {}
1650 for each in struct_list:
1651 if (tag_mode == 0 and each['tag'] >= 0x100) or \
1652 (tag_mode == 1 and each['tag'] < 0x100):
1653 continue
1654 new_dict[each['name']] = (each['alias'], each['count'])
1655 if each['alias'] not in name_dict:
1656 name_dict[each['alias']] = 1
1657 lines.extend(self.create_struct(each['alias'],
1658 each['node'], new_dict))
1659 lines.append('#pragma pack()\n\n')
1660
1661 self.write_header_file(lines, hdr_file_name)
1662
1663 def write_header_file(self, txt_body, file_name, type='h'):
1664 file_name_def = os.path.basename(file_name).replace('.', '_')
1665 file_name_def = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', file_name_def)
1666 file_name_def = re.sub('([a-z0-9])([A-Z])', r'\1_\2',
1667 file_name_def).upper()
1668
1669 lines = []
1670 lines.append("%s\n" % get_copyright_header(type))
1671 lines.append("#ifndef __%s__\n" % file_name_def)
1672 lines.append("#define __%s__\n\n" % file_name_def)
1673 if type == 'h':
1674 lines.append("#pragma pack(1)\n\n")
1675 lines.extend(txt_body)
1676 if type == 'h':
1677 lines.append("#pragma pack()\n\n")
1678 lines.append("#endif\n")
1679
1680 # Don't rewrite if the contents are the same
1681 create = True
1682 if os.path.exists(file_name):
1683 hdr_file = open(file_name, "r")
1684 org_txt = hdr_file.read()
1685 hdr_file.close()
1686
1687 new_txt = ''.join(lines)
1688 if org_txt == new_txt:
1689 create = False
1690
1691 if create:
1692 hdr_file = open(file_name, "w")
1693 hdr_file.write(''.join(lines))
1694 hdr_file.close()
1695
1696 def generate_data_inc_file(self, dat_inc_file_name, bin_file=None):
1697 # Put a prefix GUID before CFGDATA so that it can be located later on
1698 prefix = b'\xa7\xbd\x7f\x73\x20\x1e\x46\xd6\
1699 xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
1700 if bin_file:
1701 fin = open(bin_file, 'rb')
1702 bin_dat = prefix + bytearray(fin.read())
1703 fin.close()
1704 else:
1705 bin_dat = prefix + self.generate_binary_array()
1706
1707 file_name = os.path.basename(dat_inc_file_name).upper()
1708 file_name = file_name.replace('.', '_')
1709
1710 txt_lines = []
1711
1712 txt_lines.append("UINT8 mConfigDataBlob[%d] = {\n" % len(bin_dat))
1713 count = 0
1714 line = [' ']
1715 for each in bin_dat:
1716 line.append('0x%02X, ' % each)
1717 count = count + 1
1718 if (count & 0x0F) == 0:
1719 line.append('\n')
1720 txt_lines.append(''.join(line))
1721 line = [' ']
1722 if len(line) > 1:
1723 txt_lines.append(''.join(line) + '\n')
1724
1725 txt_lines.append("};\n\n")
1726 self.write_header_file(txt_lines, dat_inc_file_name, 'inc')
1727
1728 return 0
1729
1730 def get_struct_array_info(self, input):
1731 parts = input.split(':')
1732 if len(parts) > 1:
1733 var = parts[1]
1734 input = parts[0]
1735 else:
1736 var = ''
1737 array_str = input.split('[')
1738 name = array_str[0]
1739 if len(array_str) > 1:
1740 num_str = ''.join(c for c in array_str[-1] if c.isdigit())
1741 num_str = '1000' if len(num_str) == 0 else num_str
1742 array_num = int(num_str)
1743 else:
1744 array_num = 0
1745 return name, array_num, var
1746
1747 def process_multilines(self, string, max_char_length):
1748 multilines = ''
1749 string_length = len(string)
1750 current_string_start = 0
1751 string_offset = 0
1752 break_line_dict = []
1753 if len(string) <= max_char_length:
1754 while (string_offset < string_length):
1755 if string_offset >= 1:
1756 if string[string_offset - 1] == '\\' and string[
1757 string_offset] == 'n':
1758 break_line_dict.append(string_offset + 1)
1759 string_offset += 1
1760 if break_line_dict != []:
1761 for each in break_line_dict:
1762 multilines += " %s\n" % string[
1763 current_string_start:each].lstrip()
1764 current_string_start = each
1765 if string_length - current_string_start > 0:
1766 multilines += " %s\n" % string[
1767 current_string_start:].lstrip()
1768 else:
1769 multilines = " %s\n" % string
1770 else:
1771 new_line_start = 0
1772 new_line_count = 0
1773 found_space_char = False
1774 while (string_offset < string_length):
1775 if string_offset >= 1:
1776 if new_line_count >= max_char_length - 1:
1777 if string[string_offset] == ' ' and \
1778 string_length - string_offset > 10:
1779 break_line_dict.append(new_line_start
1780 + new_line_count)
1781 new_line_start = new_line_start + new_line_count
1782 new_line_count = 0
1783 found_space_char = True
1784 elif string_offset == string_length - 1 and \
1785 found_space_char is False:
1786 break_line_dict.append(0)
1787 if string[string_offset - 1] == '\\' and string[
1788 string_offset] == 'n':
1789 break_line_dict.append(string_offset + 1)
1790 new_line_start = string_offset + 1
1791 new_line_count = 0
1792 string_offset += 1
1793 new_line_count += 1
1794 if break_line_dict != []:
1795 break_line_dict.sort()
1796 for each in break_line_dict:
1797 if each > 0:
1798 multilines += " %s\n" % string[
1799 current_string_start:each].lstrip()
1800 current_string_start = each
1801 if string_length - current_string_start > 0:
1802 multilines += " %s\n" % \
1803 string[current_string_start:].lstrip()
1804 return multilines
1805
1806 def create_field(self, item, name, length, offset, struct,
1807 bsf_name, help, option, bits_length=None):
1808 pos_name = 28
1809 name_line = ''
1810 # help_line = ''
1811 # option_line = ''
1812
1813 if length == 0 and name == 'dummy':
1814 return '\n'
1815
1816 if bits_length == 0:
1817 return '\n'
1818
1819 is_array = False
1820 if length in [1, 2, 4, 8]:
1821 type = "UINT%d" % (length * 8)
1822 else:
1823 is_array = True
1824 type = "UINT8"
1825
1826 if item and item['value'].startswith('{'):
1827 type = "UINT8"
1828 is_array = True
1829
1830 if struct != '':
1831 struct_base = struct.rstrip('*')
1832 name = '*' * (len(struct) - len(struct_base)) + name
1833 struct = struct_base
1834 type = struct
1835 if struct in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
1836 is_array = True
1837 unit = int(type[4:]) // 8
1838 length = length / unit
1839 else:
1840 is_array = False
1841
1842 if is_array:
1843 name = name + '[%d]' % length
1844
1845 if len(type) < pos_name:
1846 space1 = pos_name - len(type)
1847 else:
1848 space1 = 1
1849
1850 if bsf_name != '':
1851 name_line = " %s\n" % bsf_name
1852 else:
1853 name_line = "N/A\n"
1854
1855 # if help != '':
1856 # help_line = self.process_multilines(help, 80)
1857
1858 # if option != '':
1859 # option_line = self.process_multilines(option, 80)
1860
1861 if offset is None:
1862 offset_str = '????'
1863 else:
1864 offset_str = '0x%04X' % offset
1865
1866 if bits_length is None:
1867 bits_length = ''
1868 else:
1869 bits_length = ' : %d' % bits_length
1870
1871 # return "\n/** %s%s%s**/\n %s%s%s%s;\n" % (name_line, help_line,
1872 # option_line, type, ' ' * space1, name, bits_length)
1873 return "\n /* Offset %s: %s */\n %s%s%s%s;\n" % (
1874 offset_str, name_line.strip(), type, ' ' * space1,
1875 name, bits_length)
1876
1877 def create_struct(self, cname, top, struct_dict):
1878 index = 0
1879 last = ''
1880 lines = []
1881 off_base = -1
1882
1883 if cname in struct_dict:
1884 if struct_dict[cname][2]:
1885 return []
1886 lines.append('\ntypedef struct {\n')
1887 for field in top:
1888 if field[0] == '$':
1889 continue
1890
1891 index += 1
1892
1893 t_item = top[field]
1894 if 'indx' not in t_item:
1895 if CGenYamlCfg.STRUCT not in top[field]:
1896 continue
1897
1898 if struct_dict[field][1] == 0:
1899 continue
1900
1901 append = True
1902 struct_info = top[field][CGenYamlCfg.STRUCT]
1903
1904 if 'struct' in struct_info:
1905 struct, array_num, var = self.get_struct_array_info(
1906 struct_info['struct'])
1907 if array_num > 0:
1908 if last == struct:
1909 append = False
1910 last = struct
1911 if var == '':
1912 var = field
1913
1914 field = CGenYamlCfg.format_struct_field_name(
1915 var, struct_dict[field][1])
1916 else:
1917 struct = struct_dict[field][0]
1918 field = CGenYamlCfg.format_struct_field_name(
1919 field, struct_dict[field][1])
1920
1921 if append:
1922 offset = t_item['$STRUCT']['offset'] // 8
1923 if off_base == -1:
1924 off_base = offset
1925 line = self.create_field(None, field, 0, 0, struct,
1926 '', '', '')
1927 lines.append(' %s' % line)
1928 last = struct
1929 continue
1930
1931 item = self.get_item_by_index(t_item['indx'])
1932 if item['cname'] == 'CfgHeader' and index == 1 or \
1933 (item['cname'] == 'CondValue' and index == 2):
1934 continue
1935
1936 bit_length = None
1937 length = (item['length'] + 7) // 8
1938 match = re.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)",
1939 t_item['length'])
1940 if match and match.group(2) == 'b':
1941 bit_length = int(match.group(1))
1942 if match.group(3) != '':
1943 length = CGenYamlCfg.bits_width[match.group(3)] // 8
1944 else:
1945 length = 4
1946 offset = item['offset'] // 8
1947 if off_base == -1:
1948 off_base = offset
1949 struct = item.get('struct', '')
1950 name = field
1951 prompt = item['name']
1952 help = item['help']
1953 option = item['option']
1954 line = self.create_field(item, name, length, offset, struct,
1955 prompt, help, option, bit_length)
1956 lines.append(' %s' % line)
1957 last = struct
1958
1959 lines.append('\n} %s;\n\n' % cname)
1960
1961 return lines
1962
1963 def write_fsp_sig_header_file(self, hdr_file_name):
1964 hdr_fd = open(hdr_file_name, 'w')
1965 hdr_fd.write("%s\n" % get_copyright_header('h'))
1966 hdr_fd.write("#ifndef __FSPUPD_H__\n"
1967 "#define __FSPUPD_H__\n\n"
1968 "#include <FspEas.h>\n\n"
1969 "#pragma pack(1)\n\n")
1970 lines = []
1971 for fsp_comp in 'TMS':
1972 top = self.locate_cfg_item('FSP%s_UPD' % fsp_comp)
1973 if not top:
1974 raise Exception('Could not find FSP UPD definition !')
1975 bins = self.get_field_value(top)
1976 lines.append("#define FSP%s_UPD_SIGNATURE"
1977 " 0x%016X /* '%s' */\n\n"
1978 % (fsp_comp, bytes_to_value(bins[:8]),
1979 bins[:8].decode()))
1980 hdr_fd.write(''.join(lines))
1981 hdr_fd.write("#pragma pack()\n\n"
1982 "#endif\n")
1983 hdr_fd.close()
1984
1985 def create_header_file(self, hdr_file_name, com_hdr_file_name='', path=''):
1986
1987 def _build_header_struct(name, cfgs, level):
1988 if CGenYamlCfg.STRUCT in cfgs:
1989 if 'CfgHeader' in cfgs:
1990 # collect CFGDATA TAG IDs
1991 cfghdr = self.get_item_by_index(cfgs['CfgHeader']['indx'])
1992 tag_val = array_str_to_value(cfghdr['value']) >> 20
1993 tag_dict[name] = tag_val
1994 if level == 1:
1995 tag_curr[0] = tag_val
1996 struct_dict[name] = (level, tag_curr[0], cfgs)
1997 if path == 'FSP_SIG':
1998 self.write_fsp_sig_header_file(hdr_file_name)
1999 return
2000 tag_curr = [0]
2001 tag_dict = {}
2002 struct_dict = {}
2003
2004 if path == '':
2005 top = None
2006 else:
2007 top = self.locate_cfg_item(path)
2008 if not top:
2009 raise Exception("Invalid configuration path '%s' !" % path)
2010 _build_header_struct(path, top, 0)
2011 self.traverse_cfg_tree(_build_header_struct, top)
2012
2013 if tag_curr[0] == 0:
2014 hdr_mode = 2
2015 else:
2016 hdr_mode = 1
2017
2018 if re.match('FSP[TMS]_UPD', path):
2019 hdr_mode |= 0x80
2020
2021 # filter out the items to be built for tags and structures
2022 struct_list = []
2023 for each in struct_dict:
2024 match = False
2025 for check in CGenYamlCfg.exclude_struct:
2026 if re.match(check, each):
2027 match = True
2028 if each in tag_dict:
2029 if each not in CGenYamlCfg.include_tag:
2030 del tag_dict[each]
2031 break
2032 if not match:
2033 struct_list.append({'name': each, 'alias': '', 'count': 0,
2034 'level': struct_dict[each][0],
2035 'tag': struct_dict[each][1],
2036 'node': struct_dict[each][2]})
2037
2038 # sort by level so that the bottom level struct
2039 # will be build first to satisfy dependencies
2040 struct_list = sorted(struct_list, key=lambda x: x['level'],
2041 reverse=True)
2042
2043 # Convert XXX_[0-9]+ to XXX as an array hint
2044 for each in struct_list:
2045 cfgs = each['node']
2046 if 'struct' in cfgs['$STRUCT']:
2047 each['alias'], array_num, var = self.get_struct_array_info(
2048 cfgs['$STRUCT']['struct'])
2049 else:
2050 match = re.match('(\\w+)(_\\d+)', each['name'])
2051 if match:
2052 each['alias'] = match.group(1)
2053 else:
2054 each['alias'] = each['name']
2055
2056 # count items for array build
2057 for idx, each in enumerate(struct_list):
2058 if idx > 0:
2059 last_struct = struct_list[idx-1]['node']['$STRUCT']
2060 curr_struct = each['node']['$STRUCT']
2061 if struct_list[idx-1]['alias'] == each['alias'] and \
2062 curr_struct['length'] == last_struct['length'] and \
2063 curr_struct['offset'] == last_struct['offset'] + \
2064 last_struct['length']:
2065 for idx2 in range(idx-1, -1, -1):
2066 if struct_list[idx2]['count'] > 0:
2067 struct_list[idx2]['count'] += 1
2068 break
2069 continue
2070 each['count'] = 1
2071
2072 # generate common header
2073 if com_hdr_file_name:
2074 self.write_cfg_header_file(com_hdr_file_name, 0, tag_dict,
2075 struct_list)
2076
2077 # generate platform header
2078 self.write_cfg_header_file(hdr_file_name, hdr_mode, tag_dict,
2079 struct_list)
2080
2081 return 0
2082
2083 def load_yaml(self, cfg_file):
2084 cfg_yaml = CFG_YAML()
2085 self.initialize()
2086 self._cfg_tree = cfg_yaml.load_yaml(cfg_file)
2087 self._def_dict = cfg_yaml.def_dict
2088 self._yaml_path = os.path.dirname(cfg_file)
2089 self.build_cfg_list()
2090 self.build_var_dict()
2091 self.update_def_value()
2092 return 0
2093
2094
2095 def usage():
2096 print('\n'.join([
2097 "GenYamlCfg Version 0.50",
2098 "Usage:",
2099 " GenYamlCfg GENINC BinFile IncOutFile "
2100 " [-D Macros]",
2101
2102 " GenYamlCfg GENPKL YamlFile PklOutFile "
2103 " [-D Macros]",
2104 " GenYamlCfg GENBIN YamlFile[;DltFile] BinOutFile "
2105 " [-D Macros]",
2106 " GenYamlCfg GENDLT YamlFile[;BinFile] DltOutFile "
2107 " [-D Macros]",
2108 " GenYamlCfg GENYML YamlFile YamlOutFile"
2109 " [-D Macros]",
2110 " GenYamlCfg GENHDR YamlFile HdrOutFile "
2111 " [-D Macros]"
2112 ]))
2113
2114
2115 def main():
2116 # Parse the options and args
2117 argc = len(sys.argv)
2118 if argc < 4:
2119 usage()
2120 return 1
2121
2122 gen_cfg_data = CGenYamlCfg()
2123 command = sys.argv[1].upper()
2124 out_file = sys.argv[3]
2125 if argc >= 5 and gen_cfg_data.parse_macros(sys.argv[4:]) != 0:
2126 raise Exception("ERROR: Macro parsing failed !")
2127
2128 file_list = sys.argv[2].split(';')
2129 if len(file_list) >= 2:
2130 yml_file = file_list[0]
2131 dlt_file = file_list[1]
2132 elif len(file_list) == 1:
2133 yml_file = file_list[0]
2134 dlt_file = ''
2135 else:
2136 raise Exception("ERROR: Invalid parameter '%s' !" % sys.argv[2])
2137 yml_scope = ''
2138 if '@' in yml_file:
2139 parts = yml_file.split('@')
2140 yml_file = parts[0]
2141 yml_scope = parts[1]
2142
2143 if command == "GENDLT" and yml_file.endswith('.dlt'):
2144 # It needs to expand an existing DLT file
2145 dlt_file = yml_file
2146 lines = gen_cfg_data.expand_include_files(dlt_file)
2147 write_lines(lines, out_file)
2148 return 0
2149
2150 if command == "GENYML":
2151 if not yml_file.lower().endswith('.yaml'):
2152 raise Exception('Only YAML file is supported !')
2153 gen_cfg_data.generate_yml_file(yml_file, out_file)
2154 return 0
2155
2156 bin_file = ''
2157 if (yml_file.lower().endswith('.bin')) and (command == "GENINC"):
2158 # It is binary file
2159 bin_file = yml_file
2160 yml_file = ''
2161
2162 if bin_file:
2163 gen_cfg_data.generate_data_inc_file(out_file, bin_file)
2164 return 0
2165
2166 cfg_bin_file = ''
2167 cfg_bin_file2 = ''
2168 if dlt_file:
2169 if command == "GENDLT":
2170 cfg_bin_file = dlt_file
2171 dlt_file = ''
2172 if len(file_list) >= 3:
2173 cfg_bin_file2 = file_list[2]
2174
2175 if yml_file.lower().endswith('.pkl'):
2176 with open(yml_file, "rb") as pkl_file:
2177 gen_cfg_data.__dict__ = marshal.load(pkl_file)
2178 gen_cfg_data.prepare_marshal(False)
2179
2180 # Override macro definition again for Pickle file
2181 if argc >= 5:
2182 gen_cfg_data.parse_macros(sys.argv[4:])
2183 else:
2184 gen_cfg_data.load_yaml(yml_file)
2185 if command == 'GENPKL':
2186 gen_cfg_data.prepare_marshal(True)
2187 with open(out_file, "wb") as pkl_file:
2188 marshal.dump(gen_cfg_data.__dict__, pkl_file)
2189 json_file = os.path.splitext(out_file)[0] + '.json'
2190 fo = open(json_file, 'w')
2191 path_list = []
2192 cfgs = {'_cfg_page': gen_cfg_data._cfg_page,
2193 '_cfg_list': gen_cfg_data._cfg_list,
2194 '_path_list': path_list}
2195 # optimize to reduce size
2196 path = None
2197 for each in cfgs['_cfg_list']:
2198 new_path = each['path'][:-len(each['cname'])-1]
2199 if path != new_path:
2200 path = new_path
2201 each['path'] = path
2202 path_list.append(path)
2203 else:
2204 del each['path']
2205 if each['order'] == each['offset']:
2206 del each['order']
2207 del each['offset']
2208
2209 # value is just used to indicate display type
2210 value = each['value']
2211 if value.startswith('0x'):
2212 hex_len = ((each['length'] + 7) // 8) * 2
2213 if len(value) == hex_len:
2214 value = 'x%d' % hex_len
2215 else:
2216 value = 'x'
2217 each['value'] = value
2218 elif value and value[0] in ['"', "'", '{']:
2219 each['value'] = value[0]
2220 else:
2221 del each['value']
2222
2223 fo.write(repr(cfgs))
2224 fo.close()
2225 return 0
2226
2227 if dlt_file:
2228 gen_cfg_data.override_default_value(dlt_file)
2229
2230 gen_cfg_data.detect_fsp()
2231
2232 if command == "GENBIN":
2233 if len(file_list) == 3:
2234 old_data = gen_cfg_data.generate_binary_array()
2235 fi = open(file_list[2], 'rb')
2236 new_data = bytearray(fi.read())
2237 fi.close()
2238 if len(new_data) != len(old_data):
2239 raise Exception("Binary file '%s' length does not match, \
2240 ignored !" % file_list[2])
2241 else:
2242 gen_cfg_data.load_default_from_bin(new_data)
2243 gen_cfg_data.override_default_value(dlt_file)
2244
2245 gen_cfg_data.generate_binary(out_file, yml_scope)
2246
2247 elif command == "GENDLT":
2248 full = True if 'FULL' in gen_cfg_data._macro_dict else False
2249 gen_cfg_data.generate_delta_file(out_file, cfg_bin_file,
2250 cfg_bin_file2, full)
2251
2252 elif command == "GENHDR":
2253 out_files = out_file.split(';')
2254 brd_out_file = out_files[0].strip()
2255 if len(out_files) > 1:
2256 com_out_file = out_files[1].strip()
2257 else:
2258 com_out_file = ''
2259 gen_cfg_data.create_header_file(brd_out_file, com_out_file, yml_scope)
2260
2261 elif command == "GENINC":
2262 gen_cfg_data.generate_data_inc_file(out_file)
2263
2264 elif command == "DEBUG":
2265 gen_cfg_data.print_cfgs()
2266
2267 else:
2268 raise Exception("Unsuported command '%s' !" % command)
2269
2270 return 0
2271
2272
2273 if __name__ == '__main__':
2274 sys.exit(main())