]>
git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/ConfigEditor/GenYamlCfg.py
3 # Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
4 # SPDX-License-Identifier: BSD-2-Clause-Patent
15 import tkinter
.messagebox
as messagebox
18 from datetime
import date
19 from collections
import OrderedDict
20 from CommonUtility
import value_to_bytearray
, value_to_bytes
, \
21 bytes_to_value
, get_bits_from_bytes
, set_bits_to_bytes
23 # Generated file copyright header
24 __copyright_tmp__
= """/** @file
26 Platform Configuration %s File.
28 Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
29 SPDX-License-Identifier: BSD-2-Clause-Patent
31 This file is automatically generated. Please do NOT modify !!!
37 def get_copyright_header(file_type
, allow_modify
=False):
39 'yaml': 'Boot Setting',
41 'inc': 'C Binary Blob',
42 'h': 'C Struct Header'
44 if file_type
in ['yaml', 'dlt']:
48 lines
= __copyright_tmp__
.split('\n')
50 lines
= [line
for line
in lines
if 'Please do NOT modify' not in line
]
51 copyright_hdr
= '\n'.join('%s%s' % (comment_char
, line
)
52 for line
in lines
)[:-1] + '\n'
53 return copyright_hdr
% (file_description
[file_type
], date
.today().year
)
56 def check_quote(text
):
57 if (text
[0] == "'" and text
[-1] == "'") or (text
[0] == '"'
63 def strip_quote(text
):
64 new_text
= text
.strip()
65 if check_quote(new_text
):
70 def strip_delimiter(text
, delim
):
71 new_text
= text
.strip()
73 if new_text
[0] == delim
[0] and new_text
[-1] == delim
[-1]:
78 def bytes_to_bracket_str(bytes
):
79 return '{ %s }' % (', '.join('0x%02x' % i
for i
in bytes
))
82 def array_str_to_value(val_str
):
83 val_str
= val_str
.strip()
84 val_str
= strip_delimiter(val_str
, '{}')
85 val_str
= strip_quote(val_str
)
87 for each
in val_str
.split(',')[::-1]:
89 value
= (value
<< 8) |
int(each
, 0)
93 def write_lines(lines
, file):
95 fo
.write(''.join([x
[0] for x
in lines
]))
100 if not os
.path
.exists(file):
101 test_file
= os
.path
.basename(file)
102 if os
.path
.exists(test_file
):
105 lines
= fi
.readlines()
110 def expand_file_value(path
, value_str
):
112 match
= re
.match("\\{\\s*FILE:(.+)\\}", value_str
)
114 file_list
= match
.group(1).split(',')
115 for file in file_list
:
117 bin_path
= os
.path
.join(path
, file)
118 result
.extend(bytearray(open(bin_path
, 'rb').read()))
119 print('\n\n result ', result
)
123 class ExpressionEval(ast
.NodeVisitor
):
128 ast
.Div
: op
.floordiv
,
139 ast
.Invert
: op
.invert
,
145 self
._expression
= ''
147 self
._get
_variable
= None
149 def eval(self
, expr
, vars={}):
150 self
._expression
= expr
151 if type(vars) is dict:
152 self
._namespace
= vars
153 self
._get
_variable
= None
156 self
._get
_variable
= vars
157 node
= ast
.parse(self
._expression
, mode
='eval')
158 result
= self
.visit(node
.body
)
160 print('EVAL [ %s ] = %s' % (expr
, str(result
)))
163 def visit_Name(self
, node
):
164 if self
._get
_variable
is not None:
165 return self
._get
_variable
(node
.id)
167 return self
._namespace
[node
.id]
169 def visit_Num(self
, node
):
172 def visit_NameConstant(self
, node
):
175 def visit_BoolOp(self
, node
):
177 if isinstance(node
.op
, ast
.And
):
178 for value
in node
.values
:
179 result
= self
.visit(value
)
182 elif isinstance(node
.op
, ast
.Or
):
183 for value
in node
.values
:
184 result
= self
.visit(value
)
187 return True if result
else False
189 def visit_UnaryOp(self
, node
):
190 val
= self
.visit(node
.operand
)
191 return ExpressionEval
.operators
[type(node
.op
)](val
)
193 def visit_BinOp(self
, node
):
194 lhs
= self
.visit(node
.left
)
195 rhs
= self
.visit(node
.right
)
196 return ExpressionEval
.operators
[type(node
.op
)](lhs
, rhs
)
198 def visit_Compare(self
, node
):
199 right
= self
.visit(node
.left
)
201 for operation
, comp
in zip(node
.ops
, node
.comparators
):
205 right
= self
.visit(comp
)
206 result
= ExpressionEval
.operators
[type(operation
)](left
, right
)
209 def visit_Call(self
, node
):
210 if node
.func
.id in ['ternary']:
211 condition
= self
.visit(node
.args
[0])
212 val_true
= self
.visit(node
.args
[1])
213 val_false
= self
.visit(node
.args
[2])
214 return val_true
if condition
else val_false
215 elif node
.func
.id in ['offset', 'length']:
216 if self
._get
_variable
is not None:
217 return self
._get
_variable
(node
.args
[0].s
, node
.func
.id)
219 raise ValueError("Unsupported function: " + repr(node
))
221 def generic_visit(self
, node
):
222 raise ValueError("malformed node or string: " + repr(node
))
226 TEMPLATE
= 'template'
228 VARIABLE
= 'variable'
231 self
.log_line
= False
232 self
.allow_template
= False
241 self
.re_expand
= re
.compile(
242 r
'(.+:\s+|\s*\-\s*)!expand\s+\{\s*(\w+_TMPL)\s*:\s*\[(.+)]\s*\}')
243 self
.re_include
= re
.compile(r
'(.+:\s+|\s*\-\s*)!include\s+(.+)')
246 def count_indent(line
):
247 return next((i
for i
, c
in enumerate(line
) if not c
.isspace()),
251 def substitue_args(text
, arg_dict
):
253 text
= text
.replace('$' + arg
, arg_dict
[arg
])
260 def process_include(self
, line
, insert
=True):
261 match
= self
.re_include
.match(line
)
263 raise Exception("Invalid !include format '%s' !" % line
.strip())
265 prefix
= match
.group(1)
266 include
= match
.group(2)
267 if prefix
.strip() == '-':
273 include
= strip_quote(include
)
274 request
= CFG_YAML
.count_indent(line
) + adjust
277 # remove the include line itself
278 del self
.full_lines
[-1]
280 inc_path
= os
.path
.join(self
.yaml_path
, include
)
281 if not os
.path
.exists(inc_path
):
282 # try relative path to project root
283 try_path
= os
.path
.join(os
.path
.dirname(os
.path
.realpath(__file__
)
285 if os
.path
.exists(try_path
):
288 raise Exception("ERROR: Cannot open file '%s'." % inc_path
)
290 lines
= read_lines(inc_path
)
293 for idx
, each
in enumerate(lines
):
294 start
= each
.lstrip()
295 if start
== '' or start
[0] == '#':
299 # append the content directly at the same line
303 current
= CFG_YAML
.count_indent(each
)
306 lines
= lines
[start
+1:] if same_line
else lines
[start
:]
309 request
= len(prefix
)
312 lines
= [prefix
+ '%s\n' % leading
] + [' ' * request
+
313 i
[current
:] for i
in lines
]
315 self
.lines
= lines
+ self
.lines
319 def process_expand(self
, line
):
320 match
= self
.re_expand
.match(line
)
322 raise Exception("Invalid !expand format '%s' !" % line
.strip())
324 prefix
= match
.group(1)
325 temp_name
= match
.group(2)
326 args
= match
.group(3)
328 if prefix
.strip() == '-':
332 lines
= self
.process_expand_template(temp_name
, prefix
, args
, indent
)
333 self
.lines
= lines
+ self
.lines
335 def process_expand_template(self
, temp_name
, prefix
, args
, indent
=2):
336 # expand text with arg substitution
337 if temp_name
not in self
.tmp_tree
:
338 raise Exception("Could not find template '%s' !" % temp_name
)
339 parts
= args
.split(',')
340 parts
= [i
.strip() for i
in parts
]
342 arg_dict
= dict(zip(['(%d)' % (i
+ 1) for i
in range(num
)], parts
))
343 str_data
= self
.tmp_tree
[temp_name
]
344 text
= DefTemplate(str_data
).safe_substitute(self
.def_dict
)
345 text
= CFG_YAML
.substitue_args(text
, arg_dict
)
346 target
= CFG_YAML
.count_indent(prefix
) + indent
347 current
= CFG_YAML
.count_indent(text
)
348 padding
= target
* ' '
352 leading
= [prefix
+ '\n']
353 text
= leading
+ [(padding
+ i
+ '\n')[current
:]
354 for i
in text
.splitlines()]
357 def load_file(self
, yaml_file
):
359 self
.lines
= read_lines(yaml_file
)
362 if len(self
.lines
) == 0:
367 def put_line(self
, line
):
368 self
.lines
.insert(0, line
)
370 del self
.full_lines
[-1]
373 if len(self
.lines
) == 0:
376 line
= self
.lines
.pop(0)
378 self
.full_lines
.append(line
.rstrip())
381 def get_multiple_line(self
, indent
):
385 line
= self
.peek_line()
390 newind
= CFG_YAML
.count_indent(line
)
398 def traverse_cfg_tree(self
, handler
):
399 def _traverse_cfg_tree(root
, level
=0):
402 if type(root
[key
]) is OrderedDict
:
404 handler(key
, root
[key
], level
)
405 _traverse_cfg_tree(root
[key
], level
)
407 _traverse_cfg_tree(self
.cfg_tree
)
410 def _count(name
, cfgs
, level
):
413 self
.traverse_cfg_tree(_count
)
416 def parse(self
, parent_name
='', curr
=None, level
=0):
423 line
= self
.get_line()
427 curr_line
= line
.strip()
428 if curr_line
== '' or curr_line
[0] == '#':
431 indent
= CFG_YAML
.count_indent(line
)
432 if last_indent
is None:
435 if indent
!= last_indent
:
436 # outside of current block, put the line back to queue
437 self
.put_line(' ' * indent
+ curr_line
)
439 if curr_line
.endswith(': >'):
441 old_count
= len(self
.full_lines
)
442 line
= self
.get_multiple_line(indent
)
443 if self
.log_line
and not self
.allow_template \
444 and '!include ' in line
:
445 # expand include in template
447 lines
= line
.splitlines()
448 for idx
, each
in enumerate(lines
):
449 if '!include ' in each
:
450 new_line
= ''.join(self
.process_include(each
,
452 new_lines
.append(new_line
)
454 new_lines
.append(each
)
455 self
.full_lines
= self
.full_lines
[:old_count
] + new_lines
456 curr_line
= curr_line
+ line
458 if indent
> last_indent
:
461 raise Exception('Unexpected format at line: %s'
465 self
.parse(key
, child
, level
)
467 line
= self
.peek_line()
469 curr_line
= line
.strip()
470 indent
= CFG_YAML
.count_indent(line
)
471 if indent
>= last_indent
:
481 if indent
< last_indent
:
484 marker1
= curr_line
[0]
485 marker2
= curr_line
[-1]
486 start
= 1 if marker1
== '-' else 0
487 pos
= curr_line
.find(': ')
490 key
= curr_line
[start
:pos
].strip()
491 if curr_line
[pos
+ 2] == '>':
492 curr
[key
] = curr_line
[pos
+ 3:]
494 # XXXX: !include / !expand
495 if '!include ' in curr_line
:
496 self
.process_include(line
)
497 elif '!expand ' in curr_line
:
498 if self
.allow_template
and not self
.log_line
:
499 self
.process_expand(line
)
501 value_str
= curr_line
[pos
+ 2:].strip()
502 curr
[key
] = value_str
503 if self
.log_line
and value_str
[0] == '{':
504 # expand {FILE: xxxx} format in the log line
505 if value_str
[1:].rstrip().startswith('FILE:'):
506 value_bytes
= expand_file_value(
507 self
.yaml_path
, value_str
)
508 value_str
= bytes_to_bracket_str(value_bytes
)
509 self
.full_lines
[-1] = line
[
510 :indent
] + curr_line
[:pos
+ 2] + value_str
513 child
= OrderedDict()
514 key
= curr_line
[start
:-1].strip()
516 # special virtual nodes, rename to ensure unique key
517 key
= '$ACTION_%04X' % self
.index
520 if key
not in temp_chk
:
521 # check for duplicated keys at same level
524 raise Exception("Duplicated item '%s:%s' found !"
525 % (parent_name
, key
))
528 if self
.var_dict
is None and key
== CFG_YAML
.VARIABLE
:
529 self
.var_dict
= child
530 if self
.tmp_tree
is None and key
== CFG_YAML
.TEMPLATE
:
531 self
.tmp_tree
= child
533 for each
in self
.var_dict
:
534 txt
= self
.var_dict
[each
]
536 self
.def_dict
['(%s)' % each
] = txt
537 if self
.tmp_tree
and key
== CFG_YAML
.CONFIGS
:
538 # apply template for the main configs
539 self
.allow_template
= True
542 # - !include cfg_opt.yaml
543 if '!include ' in curr_line
:
544 self
.process_include(line
)
548 def load_yaml(self
, opt_file
):
550 self
.yaml_path
= os
.path
.dirname(opt_file
)
551 self
.load_file(opt_file
)
552 yaml_tree
= self
.parse()
553 self
.tmp_tree
= yaml_tree
[CFG_YAML
.TEMPLATE
]
554 self
.cfg_tree
= yaml_tree
[CFG_YAML
.CONFIGS
]
557 def expand_yaml(self
, opt_file
):
559 self
.load_yaml(opt_file
)
560 self
.log_line
= False
561 text
= '\n'.join(self
.full_lines
)
566 class DefTemplate(string
.Template
):
567 idpattern
= '\\([_A-Z][_A-Z0-9]*\\)|[_A-Z][_A-Z0-9]*'
572 bits_width
= {'b': 1, 'B': 8, 'W': 16, 'D': 32, 'Q': 64}
573 builtin_option
= {'$EN_DIS': [('0', 'Disable'), ('1', 'Enable')]}
574 exclude_struct
= ['FSP_UPD_HEADER', 'FSPT_ARCH_UPD',
575 'FSPM_ARCH_UPD', 'FSPS_ARCH_UPD',
576 'GPIO_GPP_*', 'GPIO_CFG_DATA',
577 'GpioConfPad*', 'GpioPinConfig',
578 'BOOT_OPTION*', 'PLATFORMID_CFG_DATA', '\\w+_Half[01]']
579 include_tag
= ['GPIO_CFG_DATA']
580 keyword_set
= set(['name', 'type', 'option', 'help', 'length',
581 'value', 'order', 'struct', 'condition'])
586 self
._macro
_dict
= {}
587 self
.binseg_dict
= {}
590 def initialize(self
):
595 self
._cfg
_page
= {'root': {'title': '', 'child': []}}
602 def deep_convert_dict(layer
):
603 # convert OrderedDict to list + dict
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
})
613 def deep_convert_list(layer
):
614 if isinstance(layer
, list):
617 if isinstance(each
, dict):
618 key
= next(iter(each
))
619 od
[key
] = CGenYamlCfg
.deep_convert_list(each
[key
])
625 def expand_include_files(file_path
, cur_dir
=''):
627 cur_dir
= os
.path
.dirname(file_path
)
628 file_path
= os
.path
.basename(file_path
)
630 input_file_path
= os
.path
.join(cur_dir
, file_path
)
631 file = open(input_file_path
, "r")
632 lines
= file.readlines()
635 for line_num
, line
in enumerate(lines
):
636 match
= re
.match("^!include\\s*(.+)?$", line
.strip())
638 inc_path
= match
.group(1)
639 tmp_path
= os
.path
.join(cur_dir
, inc_path
)
641 if not os
.path
.exists(tmp_path
):
642 cur_dir
= os
.path
.join(os
.path
.dirname
643 (os
.path
.realpath(__file__
)
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
)
650 new_lines
.append(('# Included from file: %s\n' % inc_path
,
652 new_lines
.append(('# %s\n' % ('=' * 80), tmp_path
, 0))
653 new_lines
.extend(CGenYamlCfg
.expand_include_files
656 new_lines
.append((line
, input_file_path
, line_num
))
661 def format_struct_field_name(input, count
=0):
665 input = input.lower()
676 name
= '%s[%d]' % (name
, count
)
683 def set_mode(self
, mode
):
686 def get_last_error(self
):
689 def get_variable(self
, var
, attr
='value'):
690 if var
in self
._var
_dict
:
691 var
= self
._var
_dict
[var
]
694 item
= self
.locate_cfg_item(var
, False)
696 raise ValueError("Cannot find variable '%s' !" % var
)
700 item
= self
.get_item_by_index(item
['indx'])
703 elif attr
== 'length':
705 elif attr
== 'value':
706 var
= self
.get_cfg_item_value(item
)
708 raise ValueError("Unsupported variable attribute '%s' !" %
712 def eval(self
, expr
):
713 def _handler(pattern
):
718 result
= self
.get_variable(pattern
.group(target
))
720 raise ValueError('Unknown variable $(%s) !' %
721 pattern
.group(target
))
724 expr_eval
= ExpressionEval()
726 # replace known variable first
727 expr
= re
.sub(r
'\$\(([_a-zA-Z][\w\.]*)\)|\$([_a-zA-Z][\w\.]*)',
729 return expr_eval
.eval(expr
, self
.get_variable
)
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'):
743 is_expression
= False
744 match
= re
.match("(\\w+)=(.+)", macro
)
746 self
._macro
_dict
[match
.group(1)] = match
.group(2)
748 match
= re
.match("(\\w+)", macro
)
750 self
._macro
_dict
[match
.group(1)] = ''
751 if len(self
._macro
_dict
) == 0:
756 print("INFO : Macro dictionary:")
757 for each
in self
._macro
_dict
:
758 print(" $(%s) = [ %s ]"
759 % (each
, self
._macro
_dict
[each
]))
762 def get_cfg_list(self
, page_id
=None):
765 return self
._cfg
_list
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
)]
772 def get_cfg_page(self
):
773 return self
._cfg
_page
775 def get_cfg_item_length(self
, item
):
776 return item
['length']
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
)
783 def format_value_to_str(self
, value
, bit_length
, old_value
=''):
784 # value is always int
785 length
= (bit_length
+ 7) // 8
787 if old_value
.startswith('0x'):
789 elif old_value
and (old_value
[0] in ['"', "'", '{']):
794 bvalue
= value_to_bytearray(value
, length
)
795 if fmt
in ['"', "'"]:
796 svalue
= bvalue
.rstrip(b
'\x00').decode()
797 value_str
= fmt
+ svalue
+ fmt
799 value_str
= '{ ' + ', '.join(['0x%02x' % i
for i
in bvalue
]) + ' }'
802 if len(old_value
) == hex_len
+ 2:
803 fstr
= '0x%%0%dx' % hex_len
806 value_str
= fstr
% value
809 value_str
= '%d' % value
811 value_str
= '0x%x' % value
813 value_str
= '{ ' + ', '.join(['0x%02x' % i
for i
in
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
)
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())
831 bvalue
= bytearray(b
'\x00')
835 return bytes_to_value(bvalue
)
837 if value_str
[0] in '{':
838 value_str
= value_str
[1:-1].strip()
840 for each
in value_str
.split(',')[::-1]:
842 value
= (value
<< 8) |
int(each
, 0)
844 length
= (bit_length
+ 7) // 8
845 return value_to_bytearray(value
, length
)
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
)
858 bin_list
= value_str
[1:-1].split(',')
862 for idx
, element
in enumerate(bin_list
):
863 each
= element
.strip()
868 if each
[0] in "'" + '"':
869 each_value
= bytearray(each
[1:-1], 'utf-8')
871 match
= re
.match("^(.+):(\\d+)([b|B|W|D|Q])$", each
)
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)
878 cur_bit_len
= int(match
.group(2)
879 ) * CGenYamlCfg
.bits_width
[
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
):
889 each_value
= value_to_bytearray(
890 self
.eval(each
.strip()), unit_len
)
892 raise SystemExit("Exception: Value %d cannot \
893 fit into %s bytes !" % (each
, unit_len
))
898 raise SystemExit("Exception: Invalid bit \
899 field alignment '%s' !" % value_str
)
900 result
.extend(value_to_bytes(value
, bit_len
// 8))
904 result
.extend(each_value
)
906 elif check_quote(value_str
):
907 result
= bytearray(value_str
[1:-1], 'utf-8') # Excluding quotes
909 result
= value_to_bytearray(self
.eval(value_str
), length
)
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
))
920 return bytes_to_value(result
)
924 def get_cfg_item_options(self
, item
):
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'
930 tmp_list
.append((op_val
, op_str
))
932 opt_list
= item
['option'].split(',')
933 for option
in opt_list
:
934 option
= option
.strip()
936 (op_val
, op_str
) = option
.split(':')
938 raise SystemExit("Exception: Invalide \
939 option format '%s' !" % option
)
940 tmp_list
.append((op_val
, op_str
))
943 def get_page_title(self
, page_id
, top
=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']
951 result
= self
.get_page_title(page_id
, node
[page_key
])
952 if result
is not None:
956 def print_pages(self
, top
=None, level
=0):
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']))
963 self
.print_pages(node
[page_id
], level
)
966 def get_item_by_index(self
, index
):
967 return self
._cfg
_list
[index
]
969 def get_item_by_path(self
, path
):
970 node
= self
.locate_cfg_item(path
)
972 return self
.get_item_by_index(node
['indx'])
976 def locate_cfg_path(self
, item
):
977 def _locate_cfg_path(root
, level
=0):
982 if type(root
[key
]) is OrderedDict
:
985 ret
= _locate_cfg_path(root
[key
], level
)
991 return _locate_cfg_path(self
._cfg
_tree
)
993 def locate_cfg_item(self
, path
, allow_exp
=True):
994 def _locate_cfg_item(root
, path
, level
=0):
995 if len(path
) == level
:
997 next_root
= root
.get(path
[level
], None)
998 if next_root
is None:
1000 raise Exception('Not a valid CFG config option path: %s' %
1001 '.'.join(path
[:level
+1]))
1004 return _locate_cfg_item(next_root
, path
, level
+ 1)
1006 path_nodes
= path
.split('.')
1007 return _locate_cfg_item(self
._cfg
_tree
, path_nodes
)
1009 def traverse_cfg_tree(self
, handler
, top
=None):
1010 def _traverse_cfg_tree(root
, level
=0):
1013 if type(root
[key
]) is OrderedDict
:
1015 handler(key
, root
[key
], level
)
1016 _traverse_cfg_tree(root
[key
], level
)
1020 top
= self
._cfg
_tree
1021 _traverse_cfg_tree(top
)
1023 def print_cfgs(self
, root
=None, short
=True, print_level
=256):
1024 def _print_cfgs(name
, cfgs
, level
):
1027 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1032 if CGenYamlCfg
.STRUCT
in cfgs
:
1033 cfg
= cfgs
[CGenYamlCfg
.STRUCT
]
1034 offset
= int(cfg
['offset'])
1035 length
= int(cfg
['length'])
1037 value
= cfg
['value']
1040 act_cfg
= dict({'value': value
, 'offset': offset
,
1042 value
= act_cfg
['value']
1043 bit_len
= act_cfg
['length']
1044 offset
= (act_cfg
['offset'] + 7) // 8
1047 value
= self
.reformat_value_str(act_cfg
['value'],
1051 value
= act_cfg
['value']
1052 length
= bit_len
// 8
1053 bit_len
= '(%db)' % bit_len
if bit_len
% 8 else '' * 4
1054 if level
<= print_level
:
1055 if short
and len(value
) > 40:
1056 value
= '%s ... %s' % (value
[:20], value
[-20:])
1057 print('%04X:%04X%-6s %s%s : %s' % (offset
, length
, bit_len
,
1058 ' ' * level
, name
, value
))
1060 self
.traverse_cfg_tree(_print_cfgs
)
1062 def build_var_dict(self
):
1063 def _build_var_dict(name
, cfgs
, level
):
1065 if CGenYamlCfg
.STRUCT
in cfgs
:
1066 struct_info
= cfgs
[CGenYamlCfg
.STRUCT
]
1067 self
._var
_dict
['_LENGTH_%s_' % name
] = struct_info
[
1069 self
._var
_dict
['_OFFSET_%s_' % name
] = struct_info
[
1073 self
.traverse_cfg_tree(_build_var_dict
)
1074 self
._var
_dict
['_LENGTH_'] = self
._cfg
_tree
[CGenYamlCfg
.STRUCT
][
1078 def add_cfg_page(self
, child
, parent
, title
=''):
1079 def _add_cfg_page(cfg_page
, child
, parent
):
1080 key
= next(iter(cfg_page
))
1082 cfg_page
[key
]['child'].append({child
: {'title': title
,
1087 for each
in cfg_page
[key
]['child']:
1088 if _add_cfg_page(each
, child
, parent
):
1093 return _add_cfg_page(self
._cfg
_page
, child
, parent
)
1095 def set_cur_page(self
, page_str
):
1100 page_list
= page_str
.split(',')
1102 page_list
= [page_str
]
1103 for page_str
in page_list
:
1104 parts
= page_str
.split(':')
1105 if len(parts
) in [1, 3]:
1106 page
= parts
[0].strip()
1108 # it is a new page definition, add it into tree
1109 parent
= parts
[1] if parts
[1] else 'root'
1110 parent
= parent
.strip()
1111 if parts
[2][0] == '"' and parts
[2][-1] == '"':
1112 parts
[2] = parts
[2][1:-1]
1114 if not self
.add_cfg_page(page
, parent
, parts
[2]):
1115 raise SystemExit("Error: Cannot find parent page \
1118 raise SystemExit("Error: Invalid page format '%s' !"
1120 self
._cur
_page
= page
1122 def extend_variable(self
, line
):
1123 # replace all variables
1128 line_after
= DefTemplate(line
).safe_substitute(self
._def
_dict
)
1129 if line
== line_after
:
1135 def reformat_number_per_type(self
, itype
, value
):
1136 if check_quote(value
) or value
.startswith('{'):
1138 parts
= itype
.split(',')
1139 if len(parts
) > 3 and parts
[0] == 'EditNum':
1140 num_fmt
= parts
[1].strip()
1143 if num_fmt
== 'HEX' and not value
.startswith('0x'):
1144 value
= '0x%X' % int(value
, 10)
1145 elif num_fmt
== 'DEC' and value
.startswith('0x'):
1146 value
= '%d' % int(value
, 16)
1149 def add_cfg_item(self
, name
, item
, offset
, path
):
1151 self
.set_cur_page(item
.get('page', ''))
1154 # skip all virtual node
1157 if not set(item
).issubset(CGenYamlCfg
.keyword_set
):
1158 for each
in list(item
):
1159 if each
not in CGenYamlCfg
.keyword_set
:
1160 raise Exception("Invalid attribute '%s' for '%s'!" %
1161 (each
, '.'.join(path
)))
1163 length
= item
.get('length', 0)
1164 if type(length
) is str:
1165 match
= re
.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)\\s*$", length
)
1167 unit_len
= CGenYamlCfg
.bits_width
[match
.group(2)]
1168 length
= int(match
.group(1), 10) * unit_len
1171 length
= int(length
, 0) * 8
1173 raise Exception("Invalid length field '%s' for '%s' !" %
1174 (length
, '.'.join(path
)))
1177 raise Exception("Invalid alignment for field '%s' for \
1178 '%s' !" % (name
, '.'.join(path
)))
1180 # define is length in bytes
1183 if not name
.isidentifier():
1184 raise Exception("Invalid config name '%s' for '%s' !" %
1185 (name
, '.'.join(path
)))
1187 itype
= str(item
.get('type', 'Reserved'))
1188 value
= str(item
.get('value', ''))
1190 if not (check_quote(value
) or value
.startswith('{')):
1192 value
= '{ %s }' % value
1194 value
= self
.reformat_number_per_type(itype
, value
)
1196 help = str(item
.get('help', ''))
1198 help = ' '.join([i
.strip() for i
in help.splitlines()])
1200 option
= str(item
.get('option', ''))
1202 option
= ' '.join([i
.strip() for i
in option
.splitlines()])
1204 # extend variables for value and condition
1205 condition
= str(item
.get('condition', ''))
1207 condition
= self
.extend_variable(condition
)
1208 value
= self
.extend_variable(value
)
1210 order
= str(item
.get('order', ''))
1213 (major
, minor
) = order
.split('.')
1214 order
= int(major
, 16)
1216 order
= int(order
, 16)
1221 cfg_item
['length'] = length
1222 cfg_item
['offset'] = offset
1223 cfg_item
['value'] = value
1224 cfg_item
['type'] = itype
1225 cfg_item
['cname'] = str(name
)
1226 cfg_item
['name'] = str(item
.get('name', ''))
1227 cfg_item
['help'] = help
1228 cfg_item
['option'] = option
1229 cfg_item
['page'] = self
._cur
_page
1230 cfg_item
['order'] = order
1231 cfg_item
['path'] = '.'.join(path
)
1232 cfg_item
['condition'] = condition
1233 if 'struct' in item
:
1234 cfg_item
['struct'] = item
['struct']
1235 self
._cfg
_list
.append(cfg_item
)
1237 item
['indx'] = len(self
._cfg
_list
) - 1
1239 # remove used info for reducing pkl size
1240 item
.pop('option', None)
1241 item
.pop('condition', None)
1242 item
.pop('help', None)
1243 item
.pop('name', None)
1244 item
.pop('page', None)
1248 def build_cfg_list(self
, cfg_name
='', top
=None, path
=[],
1249 info
={'offset': 0}):
1251 top
= self
._cfg
_tree
1253 info
= {'offset': 0}
1255 start
= info
['offset']
1259 if type(top
[key
]) is OrderedDict
:
1261 self
.build_cfg_list(key
, top
[key
], path
, info
)
1265 length
= self
.add_cfg_item(cfg_name
, top
, info
['offset'], path
)
1266 info
['offset'] += length
1267 elif cfg_name
== '' or (cfg_name
and cfg_name
[0] != '$'):
1268 # check first element for struct
1269 first
= next(iter(top
))
1270 struct_str
= CGenYamlCfg
.STRUCT
1271 if first
!= struct_str
:
1272 struct_node
= OrderedDict({})
1273 top
[struct_str
] = struct_node
1274 top
.move_to_end(struct_str
, False)
1276 struct_node
= top
[struct_str
]
1277 struct_node
['offset'] = start
1278 struct_node
['length'] = info
['offset'] - start
1279 if struct_node
['length'] % 8 != 0:
1280 raise SystemExit("Error: Bits length not aligned for %s !" %
1283 def get_field_value(self
, top
=None):
1284 def _get_field_value(name
, cfgs
, level
):
1286 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1287 if act_cfg
['length'] == 0:
1289 value
= self
.get_value(act_cfg
['value'], act_cfg
['length'],
1291 set_bits_to_bytes(result
, act_cfg
['offset'] -
1292 struct_info
['offset'], act_cfg
['length'],
1296 top
= self
._cfg
_tree
1297 struct_info
= top
[CGenYamlCfg
.STRUCT
]
1298 result
= bytearray((struct_info
['length'] + 7) // 8)
1299 self
.traverse_cfg_tree(_get_field_value
, top
)
1304 def find_data_difference(self
, act_val
, act_cfg
):
1305 # checks for any difference between BSF and Binary file
1307 if act_val
!= act_cfg
['value']:
1309 if 'DEC' in act_cfg
['type']:
1310 bsf_val
= '0x%x' % int(act_val
)
1311 if bsf_val
!= act_cfg
['value']:
1312 config_val
= bsf_val
1316 config_val
= act_val
1318 available_fv1
= 'none'
1319 available_fv2
= 'none'
1321 if self
.detect_fsp():
1322 if len(self
.available_fv
) >= 1:
1323 if len(self
.available_fv
) > 1:
1324 available_fv1
= self
.available_fv
[1]
1325 if self
.available_fv
[2]:
1326 available_fv2
= self
.available_fv
[2]
1328 available_fv1
= self
.available_fv
[1]
1329 if act_cfg
['length'] == 16:
1330 config_val
= int(config_val
, 16)
1331 config_val
= '0x%x' % config_val
1332 act_cfg
['value'] = int(
1333 act_cfg
['value'], 16)
1334 act_cfg
['value'] = '0x%x' % \
1338 string
= ('.' + act_cfg
['cname'])
1339 if (act_cfg
['path'].endswith(self
.available_fv
[0] + string
)
1340 or act_cfg
['path'].endswith(available_fv1
+ string
)
1341 or act_cfg
['path'].endswith(available_fv2
+ string
)) \
1342 and 'BsfSkip' not in act_cfg
['cname'] \
1343 and 'Reserved' not in act_cfg
['name']:
1344 if act_cfg
['option'] != '':
1345 if act_cfg
['length'] == 8:
1346 config_val
= int(config_val
, 16)
1347 config_val
= '0x%x' % config_val
1348 act_cfg
['value'] = int(
1349 act_cfg
['value'], 16)
1350 act_cfg
['value'] = '0x%x' % \
1352 option
= act_cfg
['option']
1356 for i
in option
.split(','):
1357 if act_cfg
['value'] in i
:
1359 elif config_val
in i
:
1361 if cfg_val
!= '' and bin_val
!= '':
1362 self
.data_diff
+= '\n\nBinary: ' \
1364 + ': ' + bin_val
.replace(' ', '') \
1365 + '\nConfig file: ' \
1366 + act_cfg
['name'] + ': ' \
1367 + cfg_val
.replace(' ', '') + '\n'
1369 self
.data_diff
+= '\n\nBinary: ' \
1370 + act_cfg
['name'] + ': ' + act_cfg
['value'] \
1371 + '\nConfig file: ' + act_cfg
['name'] \
1372 + ': ' + config_val
+ '\n'
1374 def set_field_value(self
, top
, value_bytes
, force
=False):
1375 def _set_field_value(name
, cfgs
, level
):
1376 if 'indx' not in cfgs
:
1378 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1379 actual_offset
= act_cfg
['offset'] - struct_info
['offset']
1380 if force
or act_cfg
['value'] == '':
1381 value
= get_bits_from_bytes(full_bytes
,
1384 act_val
= act_cfg
['value']
1386 act_val
= '%d' % value
1387 act_val
= self
.reformat_number_per_type(act_cfg
1390 act_cfg
['value'] = self
.format_value_to_str(
1391 value
, act_cfg
['length'], act_val
)
1392 self
.find_data_difference(act_val
, act_cfg
)
1395 # it is config option
1396 value
= bytes_to_value(value_bytes
)
1397 act_cfg
= self
.get_item_by_index(top
['indx'])
1398 act_cfg
['value'] = self
.format_value_to_str(
1399 value
, act_cfg
['length'], act_cfg
['value'])
1402 struct_info
= top
[CGenYamlCfg
.STRUCT
]
1403 length
= struct_info
['length'] // 8
1404 full_bytes
= bytearray(value_bytes
[:length
])
1405 if len(full_bytes
) < length
:
1406 full_bytes
.extend(bytearray(length
- len(value_bytes
)))
1407 self
.traverse_cfg_tree(_set_field_value
, top
)
1409 def update_def_value(self
):
1410 def _update_def_value(name
, cfgs
, level
):
1412 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1413 if act_cfg
['value'] != '' and act_cfg
['length'] > 0:
1415 act_cfg
['value'] = self
.reformat_value_str(
1416 act_cfg
['value'], act_cfg
['length'])
1418 raise Exception("Invalid value expression '%s' \
1419 for '%s' !" % (act_cfg
['value'], act_cfg
['path']))
1421 if CGenYamlCfg
.STRUCT
in cfgs
and 'value' in \
1422 cfgs
[CGenYamlCfg
.STRUCT
]:
1423 curr
= cfgs
[CGenYamlCfg
.STRUCT
]
1424 value_bytes
= self
.get_value(curr
['value'],
1425 curr
['length'], True)
1426 self
.set_field_value(cfgs
, value_bytes
)
1428 self
.traverse_cfg_tree(_update_def_value
, self
._cfg
_tree
)
1430 def evaluate_condition(self
, item
):
1431 expr
= item
['condition']
1432 result
= self
.parse_value(expr
, 1, False)
1435 def detect_fsp(self
):
1436 cfg_segs
= self
.get_cfg_segment()
1437 if len(cfg_segs
) == 3:
1439 for idx
, seg
in enumerate(cfg_segs
):
1440 if not seg
[0].endswith('UPD_%s' % 'TMS'[idx
]):
1446 self
.set_mode('FSP')
1449 def get_cfg_segment(self
):
1450 def _get_cfg_segment(name
, cfgs
, level
):
1451 if 'indx' not in cfgs
:
1452 if name
.startswith('$ACTION_'):
1454 find
[0] = cfgs
['find']
1457 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1458 segments
.append([find
[0], act_cfg
['offset'] // 8, 0])
1464 self
.traverse_cfg_tree(_get_cfg_segment
, self
._cfg
_tree
)
1465 cfg_len
= self
._cfg
_tree
[CGenYamlCfg
.STRUCT
]['length'] // 8
1466 if len(segments
) == 0:
1467 segments
.append(['', 0, cfg_len
])
1469 segments
.append(['', cfg_len
, 0])
1471 for idx
, each
in enumerate(segments
[:-1]):
1472 cfg_segs
.append((each
[0], each
[1],
1473 segments
[idx
+1][1] - each
[1]))
1477 def get_bin_segment(self
, bin_data
):
1478 cfg_segs
= self
.get_cfg_segment()
1480 for seg
in cfg_segs
:
1481 key
= seg
[0].encode()
1483 bin_segs
.append([seg
[0], 0, len(bin_data
)])
1485 pos
= bin_data
.find(key
)
1487 # ensure no other match for the key
1488 next_pos
= bin_data
.find(key
, pos
+ len(seg
[0]))
1490 if key
== b
'$SKLFSP$' or key
== b
'$BSWFSP$':
1491 string
= ('Warning: Multiple matches for %s in '
1492 'binary!\n\nA workaround applied to such '
1493 'FSP 1.x binary to use second'
1494 ' match instead of first match!' % key
)
1495 messagebox
.showwarning('Warning!', string
)
1498 print("Warning: Multiple matches for '%s' "
1499 "in binary, the 1st instance will be used !"
1501 bin_segs
.append([seg
[0], pos
, seg
[2]])
1502 self
.binseg_dict
[seg
[0]] = pos
1504 bin_segs
.append([seg
[0], -1, seg
[2]])
1505 self
.binseg_dict
[seg
[0]] = -1
1513 def extract_cfg_from_bin(self
, bin_data
):
1514 # get cfg bin length
1515 cfg_bins
= bytearray()
1516 bin_segs
= self
.get_bin_segment(bin_data
)
1518 for each
in bin_segs
:
1520 cfg_bins
.extend(bin_data
[each
[1]:each
[1] + each
[2]])
1521 self
.available_fv
.append(each
[0])
1523 self
.missing_fv
.append(each
[0])
1524 string
= each
[0] + ' is not availabe.'
1525 messagebox
.showinfo('', string
)
1526 cfg_bins
.extend(bytearray(each
[2]))
1527 Dummy_offset
+= each
[2]
1530 def save_current_to_bin(self
):
1531 cfg_bins
= self
.generate_binary_array()
1532 if self
._old
_bin
is None:
1535 bin_data
= bytearray(self
._old
_bin
)
1536 bin_segs
= self
.get_bin_segment(self
._old
_bin
)
1538 for each
in bin_segs
:
1541 bin_data
[each
[1]:each
[1] + length
] = cfg_bins
[cfg_off
:
1548 print('Patched the loaded binary successfully !')
1551 def show_data_difference(self
, data_diff
):
1552 # Displays if any data difference detected in BSF and Binary file
1553 pop_up_text
= 'There are differences in Config file and binary '\
1555 pop_up_text
+= data_diff
1557 window
= tkinter
.Tk()
1558 window
.title("Data Difference")
1559 window
.resizable(1, 1)
1561 window
.geometry("800x400")
1562 frame
= tkinter
.Frame(window
, height
=800, width
=700)
1563 frame
.pack(side
=tkinter
.BOTTOM
)
1564 # Vertical (y) Scroll Bar
1565 scroll
= tkinter
.Scrollbar(window
)
1566 scroll
.pack(side
=tkinter
.RIGHT
, fill
=tkinter
.Y
)
1568 text
= tkinter
.Text(window
, wrap
=tkinter
.NONE
,
1569 yscrollcommand
=scroll
.set,
1570 width
=700, height
=400)
1571 text
.insert(tkinter
.INSERT
, pop_up_text
)
1573 # Configure the scrollbars
1574 scroll
.config(command
=text
.yview
)
1575 exit_button
= tkinter
.Button(
1576 window
, text
="Close", command
=window
.destroy
)
1577 exit_button
.pack(in_
=frame
, side
=tkinter
.RIGHT
, padx
=20, pady
=10)
1579 def load_default_from_bin(self
, bin_data
):
1580 self
._old
_bin
= bin_data
1581 cfg_bins
= self
.extract_cfg_from_bin(bin_data
)
1582 self
.set_field_value(self
._cfg
_tree
, cfg_bins
, True)
1585 self
.show_data_difference(self
.data_diff
)
1588 def generate_binary_array(self
, path
=''):
1592 top
= self
.locate_cfg_item(path
)
1594 raise Exception("Invalid configuration path '%s' !"
1597 return self
.get_field_value(top
)
1599 def generate_binary(self
, bin_file_name
, path
=''):
1600 bin_file
= open(bin_file_name
, "wb")
1601 bin_file
.write(self
.generate_binary_array(path
))
1605 def write_delta_file(self
, out_file
, platform_id
, out_lines
):
1606 dlt_fd
= open(out_file
, "w")
1607 dlt_fd
.write("%s\n" % get_copyright_header('dlt', True))
1608 if platform_id
is not None:
1610 dlt_fd
.write('# Delta configuration values for '
1611 'platform ID 0x%04X\n'
1613 dlt_fd
.write('#\n\n')
1614 for line
in out_lines
:
1615 dlt_fd
.write('%s\n' % line
)
1618 def override_default_value(self
, dlt_file
):
1620 dlt_lines
= CGenYamlCfg
.expand_include_files(dlt_file
)
1623 for line
, file_path
, line_num
in dlt_lines
:
1625 if not line
or line
.startswith('#'):
1627 match
= re
.match("\\s*([\\w\\.]+)\\s*\\|\\s*(.+)", line
)
1629 raise Exception("Unrecognized line '%s' "
1630 "(File:'%s' Line:%d) !"
1631 % (line
, file_path
, line_num
+ 1))
1633 path
= match
.group(1)
1634 value_str
= match
.group(2)
1635 top
= self
.locate_cfg_item(path
)
1638 "Invalid configuration '%s' (File:'%s' Line:%d) !" %
1639 (path
, file_path
, line_num
+ 1))
1642 act_cfg
= self
.get_item_by_index(top
['indx'])
1643 bit_len
= act_cfg
['length']
1645 struct_info
= top
[CGenYamlCfg
.STRUCT
]
1646 bit_len
= struct_info
['length']
1648 value_bytes
= self
.parse_value(value_str
, bit_len
)
1649 self
.set_field_value(top
, value_bytes
, True)
1651 if path
== 'PLATFORMID_CFG_DATA.PlatformId':
1652 platform_id
= value_str
1654 if platform_id
is None:
1656 "PLATFORMID_CFG_DATA.PlatformId is missing "
1662 def generate_delta_file_from_bin(self
, delta_file
, old_data
,
1663 new_data
, full
=False):
1664 new_data
= self
.load_default_from_bin(new_data
)
1669 for item
in self
._cfg
_list
:
1670 if not full
and (item
['type'] in ['Reserved']):
1672 old_val
= get_bits_from_bytes(old_data
, item
['offset'],
1674 new_val
= get_bits_from_bytes(new_data
, item
['offset'],
1677 full_name
= item
['path']
1678 if 'PLATFORMID_CFG_DATA.PlatformId' == full_name
:
1679 def_platform_id
= old_val
1680 if new_val
!= old_val
or full
:
1681 val_str
= self
.reformat_value_str(item
['value'],
1683 text
= '%-40s | %s' % (full_name
, val_str
)
1686 if self
.get_mode() != 'FSP':
1687 if platform_id
is None or def_platform_id
== platform_id
:
1688 platform_id
= def_platform_id
1689 print("WARNING: 'PlatformId' configuration is "
1690 "same as default %d!" % platform_id
)
1692 lines
.insert(0, '%-40s | %s\n\n' %
1693 ('PLATFORMID_CFG_DATA.PlatformId',
1694 '0x%04X' % platform_id
))
1698 self
.write_delta_file(delta_file
, platform_id
, lines
)
1702 def generate_delta_file(self
, delta_file
, bin_file
, bin_file2
, full
=False):
1703 fd
= open(bin_file
, 'rb')
1704 new_data
= self
.extract_cfg_from_bin(bytearray(fd
.read()))
1708 old_data
= self
.generate_binary_array()
1711 fd
= open(bin_file2
, 'rb')
1712 new_data
= self
.extract_cfg_from_bin(bytearray(fd
.read()))
1715 return self
.generate_delta_file_from_bin(delta_file
,
1716 old_data
, new_data
, full
)
1718 def prepare_marshal(self
, is_save
):
1720 # Ordered dict is not marshallable, convert to list
1721 self
._cfg
_tree
= CGenYamlCfg
.deep_convert_dict(self
._cfg
_tree
)
1724 self
._cfg
_tree
= CGenYamlCfg
.deep_convert_list(self
._cfg
_tree
)
1726 def generate_yml_file(self
, in_file
, out_file
):
1727 cfg_yaml
= CFG_YAML()
1728 text
= cfg_yaml
.expand_yaml(in_file
)
1729 yml_fd
= open(out_file
, "w")
1734 def write_cfg_header_file(self
, hdr_file_name
, tag_mode
,
1735 tag_dict
, struct_list
):
1737 lines
.append('\n\n')
1738 if self
.get_mode() == 'FSP':
1739 lines
.append('#include <FspUpd.h>\n')
1741 tag_mode
= tag_mode
& 0x7F
1742 tag_list
= sorted(list(tag_dict
.items()), key
=lambda x
: x
[1])
1743 for tagname
, tagval
in tag_list
:
1744 if (tag_mode
== 0 and tagval
>= 0x100) or \
1745 (tag_mode
== 1 and tagval
< 0x100):
1747 lines
.append('#define %-30s 0x%03X\n' % (
1748 'CDATA_%s_TAG' % tagname
[:-9], tagval
))
1749 lines
.append('\n\n')
1753 for each
in struct_list
:
1754 if (tag_mode
== 0 and each
['tag'] >= 0x100) or \
1755 (tag_mode
== 1 and each
['tag'] < 0x100):
1757 new_dict
[each
['name']] = (each
['alias'], each
['count'])
1758 if each
['alias'] not in name_dict
:
1759 name_dict
[each
['alias']] = 1
1760 lines
.extend(self
.create_struct(each
['alias'],
1761 each
['node'], new_dict
))
1762 lines
.append('#pragma pack()\n\n')
1764 self
.write_header_file(lines
, hdr_file_name
)
1766 def write_header_file(self
, txt_body
, file_name
, type='h'):
1767 file_name_def
= os
.path
.basename(file_name
).replace('.', '_')
1768 file_name_def
= re
.sub('(.)([A-Z][a-z]+)', r
'\1_\2', file_name_def
)
1769 file_name_def
= re
.sub('([a-z0-9])([A-Z])', r
'\1_\2',
1770 file_name_def
).upper()
1773 lines
.append("%s\n" % get_copyright_header(type))
1774 lines
.append("#ifndef __%s__\n" % file_name_def
)
1775 lines
.append("#define __%s__\n\n" % file_name_def
)
1777 lines
.append("#pragma pack(1)\n\n")
1778 lines
.extend(txt_body
)
1780 lines
.append("#pragma pack()\n\n")
1781 lines
.append("#endif\n")
1783 # Don't rewrite if the contents are the same
1785 if os
.path
.exists(file_name
):
1786 hdr_file
= open(file_name
, "r")
1787 org_txt
= hdr_file
.read()
1790 new_txt
= ''.join(lines
)
1791 if org_txt
== new_txt
:
1795 hdr_file
= open(file_name
, "w")
1796 hdr_file
.write(''.join(lines
))
1799 def generate_data_inc_file(self
, dat_inc_file_name
, bin_file
=None):
1800 # Put a prefix GUID before CFGDATA so that it can be located later on
1801 prefix
= b
'\xa7\xbd\x7f\x73\x20\x1e\x46\xd6\
1802 xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
1804 fin
= open(bin_file
, 'rb')
1805 bin_dat
= prefix
+ bytearray(fin
.read())
1808 bin_dat
= prefix
+ self
.generate_binary_array()
1810 file_name
= os
.path
.basename(dat_inc_file_name
).upper()
1811 file_name
= file_name
.replace('.', '_')
1815 txt_lines
.append("UINT8 mConfigDataBlob[%d] = {\n" % len(bin_dat
))
1818 for each
in bin_dat
:
1819 line
.append('0x%02X, ' % each
)
1821 if (count
& 0x0F) == 0:
1823 txt_lines
.append(''.join(line
))
1826 txt_lines
.append(''.join(line
) + '\n')
1828 txt_lines
.append("};\n\n")
1829 self
.write_header_file(txt_lines
, dat_inc_file_name
, 'inc')
1833 def get_struct_array_info(self
, input):
1834 parts
= input.split(':')
1840 array_str
= input.split('[')
1842 if len(array_str
) > 1:
1843 num_str
= ''.join(c
for c
in array_str
[-1] if c
.isdigit())
1844 num_str
= '1000' if len(num_str
) == 0 else num_str
1845 array_num
= int(num_str
)
1848 return name
, array_num
, var
1850 def process_multilines(self
, string
, max_char_length
):
1852 string_length
= len(string
)
1853 current_string_start
= 0
1855 break_line_dict
= []
1856 if len(string
) <= max_char_length
:
1857 while (string_offset
< string_length
):
1858 if string_offset
>= 1:
1859 if string
[string_offset
- 1] == '\\' and string
[
1860 string_offset
] == 'n':
1861 break_line_dict
.append(string_offset
+ 1)
1863 if break_line_dict
!= []:
1864 for each
in break_line_dict
:
1865 multilines
+= " %s\n" % string
[
1866 current_string_start
:each
].lstrip()
1867 current_string_start
= each
1868 if string_length
- current_string_start
> 0:
1869 multilines
+= " %s\n" % string
[
1870 current_string_start
:].lstrip()
1872 multilines
= " %s\n" % string
1876 found_space_char
= False
1877 while (string_offset
< string_length
):
1878 if string_offset
>= 1:
1879 if new_line_count
>= max_char_length
- 1:
1880 if string
[string_offset
] == ' ' and \
1881 string_length
- string_offset
> 10:
1882 break_line_dict
.append(new_line_start
1884 new_line_start
= new_line_start
+ new_line_count
1886 found_space_char
= True
1887 elif string_offset
== string_length
- 1 and \
1888 found_space_char
is False:
1889 break_line_dict
.append(0)
1890 if string
[string_offset
- 1] == '\\' and string
[
1891 string_offset
] == 'n':
1892 break_line_dict
.append(string_offset
+ 1)
1893 new_line_start
= string_offset
+ 1
1897 if break_line_dict
!= []:
1898 break_line_dict
.sort()
1899 for each
in break_line_dict
:
1901 multilines
+= " %s\n" % string
[
1902 current_string_start
:each
].lstrip()
1903 current_string_start
= each
1904 if string_length
- current_string_start
> 0:
1905 multilines
+= " %s\n" % \
1906 string
[current_string_start
:].lstrip()
1909 def create_field(self
, item
, name
, length
, offset
, struct
,
1910 bsf_name
, help, option
, bits_length
=None):
1916 if length
== 0 and name
== 'dummy':
1919 if bits_length
== 0:
1923 if length
in [1, 2, 4, 8]:
1924 type = "UINT%d" % (length
* 8)
1929 if item
and item
['value'].startswith('{'):
1934 struct_base
= struct
.rstrip('*')
1935 name
= '*' * (len(struct
) - len(struct_base
)) + name
1936 struct
= struct_base
1938 if struct
in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
1940 unit
= int(type[4:]) // 8
1941 length
= length
/ unit
1946 name
= name
+ '[%d]' % length
1948 if len(type) < pos_name
:
1949 space1
= pos_name
- len(type)
1954 name_line
= " %s\n" % bsf_name
1959 # help_line = self.process_multilines(help, 80)
1962 # option_line = self.process_multilines(option, 80)
1967 offset_str
= '0x%04X' % offset
1969 if bits_length
is None:
1972 bits_length
= ' : %d' % bits_length
1974 # return "\n/** %s%s%s**/\n %s%s%s%s;\n" % (name_line, help_line,
1975 # option_line, type, ' ' * space1, name, bits_length)
1976 return "\n /* Offset %s: %s */\n %s%s%s%s;\n" % (
1977 offset_str
, name_line
.strip(), type, ' ' * space1
,
1980 def create_struct(self
, cname
, top
, struct_dict
):
1986 if cname
in struct_dict
:
1987 if struct_dict
[cname
][2]:
1989 lines
.append('\ntypedef struct {\n')
1997 if 'indx' not in t_item
:
1998 if CGenYamlCfg
.STRUCT
not in top
[field
]:
2001 if struct_dict
[field
][1] == 0:
2005 struct_info
= top
[field
][CGenYamlCfg
.STRUCT
]
2007 if 'struct' in struct_info
:
2008 struct
, array_num
, var
= self
.get_struct_array_info(
2009 struct_info
['struct'])
2017 field
= CGenYamlCfg
.format_struct_field_name(
2018 var
, struct_dict
[field
][1])
2020 struct
= struct_dict
[field
][0]
2021 field
= CGenYamlCfg
.format_struct_field_name(
2022 field
, struct_dict
[field
][1])
2025 offset
= t_item
['$STRUCT']['offset'] // 8
2028 line
= self
.create_field(None, field
, 0, 0, struct
,
2030 lines
.append(' %s' % line
)
2034 item
= self
.get_item_by_index(t_item
['indx'])
2035 if item
['cname'] == 'CfgHeader' and index
== 1 or \
2036 (item
['cname'] == 'CondValue' and index
== 2):
2040 length
= (item
['length'] + 7) // 8
2041 match
= re
.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)",
2043 if match
and match
.group(2) == 'b':
2044 bit_length
= int(match
.group(1))
2045 if match
.group(3) != '':
2046 length
= CGenYamlCfg
.bits_width
[match
.group(3)] // 8
2049 offset
= item
['offset'] // 8
2052 struct
= item
.get('struct', '')
2054 prompt
= item
['name']
2056 option
= item
['option']
2057 line
= self
.create_field(item
, name
, length
, offset
, struct
,
2058 prompt
, help, option
, bit_length
)
2059 lines
.append(' %s' % line
)
2062 lines
.append('\n} %s;\n\n' % cname
)
2066 def write_fsp_sig_header_file(self
, hdr_file_name
):
2067 hdr_fd
= open(hdr_file_name
, 'w')
2068 hdr_fd
.write("%s\n" % get_copyright_header('h'))
2069 hdr_fd
.write("#ifndef __FSPUPD_H__\n"
2070 "#define __FSPUPD_H__\n\n"
2071 "#include <FspEas.h>\n\n"
2072 "#pragma pack(1)\n\n")
2074 for fsp_comp
in 'TMS':
2075 top
= self
.locate_cfg_item('FSP%s_UPD' % fsp_comp
)
2077 raise Exception('Could not find FSP UPD definition !')
2078 bins
= self
.get_field_value(top
)
2079 lines
.append("#define FSP%s_UPD_SIGNATURE"
2080 " 0x%016X /* '%s' */\n\n"
2081 % (fsp_comp
, bytes_to_value(bins
[:8]),
2083 hdr_fd
.write(''.join(lines
))
2084 hdr_fd
.write("#pragma pack()\n\n"
2088 def create_header_file(self
, hdr_file_name
, com_hdr_file_name
='', path
=''):
2090 def _build_header_struct(name
, cfgs
, level
):
2091 if CGenYamlCfg
.STRUCT
in cfgs
:
2092 if 'CfgHeader' in cfgs
:
2093 # collect CFGDATA TAG IDs
2094 cfghdr
= self
.get_item_by_index(cfgs
['CfgHeader']['indx'])
2095 tag_val
= array_str_to_value(cfghdr
['value']) >> 20
2096 tag_dict
[name
] = tag_val
2098 tag_curr
[0] = tag_val
2099 struct_dict
[name
] = (level
, tag_curr
[0], cfgs
)
2100 if path
== 'FSP_SIG':
2101 self
.write_fsp_sig_header_file(hdr_file_name
)
2110 top
= self
.locate_cfg_item(path
)
2112 raise Exception("Invalid configuration path '%s' !" % path
)
2113 _build_header_struct(path
, top
, 0)
2114 self
.traverse_cfg_tree(_build_header_struct
, top
)
2116 if tag_curr
[0] == 0:
2121 if re
.match('FSP[TMS]_UPD', path
):
2124 # filter out the items to be built for tags and structures
2126 for each
in struct_dict
:
2128 for check
in CGenYamlCfg
.exclude_struct
:
2129 if re
.match(check
, each
):
2131 if each
in tag_dict
:
2132 if each
not in CGenYamlCfg
.include_tag
:
2136 struct_list
.append({'name': each
, 'alias': '', 'count': 0,
2137 'level': struct_dict
[each
][0],
2138 'tag': struct_dict
[each
][1],
2139 'node': struct_dict
[each
][2]})
2141 # sort by level so that the bottom level struct
2142 # will be build first to satisfy dependencies
2143 struct_list
= sorted(struct_list
, key
=lambda x
: x
['level'],
2146 # Convert XXX_[0-9]+ to XXX as an array hint
2147 for each
in struct_list
:
2149 if 'struct' in cfgs
['$STRUCT']:
2150 each
['alias'], array_num
, var
= self
.get_struct_array_info(
2151 cfgs
['$STRUCT']['struct'])
2153 match
= re
.match('(\\w+)(_\\d+)', each
['name'])
2155 each
['alias'] = match
.group(1)
2157 each
['alias'] = each
['name']
2159 # count items for array build
2160 for idx
, each
in enumerate(struct_list
):
2162 last_struct
= struct_list
[idx
-1]['node']['$STRUCT']
2163 curr_struct
= each
['node']['$STRUCT']
2164 if struct_list
[idx
-1]['alias'] == each
['alias'] and \
2165 curr_struct
['length'] == last_struct
['length'] and \
2166 curr_struct
['offset'] == last_struct
['offset'] + \
2167 last_struct
['length']:
2168 for idx2
in range(idx
-1, -1, -1):
2169 if struct_list
[idx2
]['count'] > 0:
2170 struct_list
[idx2
]['count'] += 1
2175 # generate common header
2176 if com_hdr_file_name
:
2177 self
.write_cfg_header_file(com_hdr_file_name
, 0, tag_dict
,
2180 # generate platform header
2181 self
.write_cfg_header_file(hdr_file_name
, hdr_mode
, tag_dict
,
2186 def load_yaml(self
, cfg_file
):
2187 cfg_yaml
= CFG_YAML()
2189 self
._cfg
_tree
= cfg_yaml
.load_yaml(cfg_file
)
2190 self
._def
_dict
= cfg_yaml
.def_dict
2191 self
._yaml
_path
= os
.path
.dirname(cfg_file
)
2192 self
.build_cfg_list()
2193 self
.build_var_dict()
2194 self
.update_def_value()
2200 "GenYamlCfg Version 0.50",
2202 " GenYamlCfg GENINC BinFile IncOutFile "
2205 " GenYamlCfg GENPKL YamlFile PklOutFile "
2207 " GenYamlCfg GENBIN YamlFile[;DltFile] BinOutFile "
2209 " GenYamlCfg GENDLT YamlFile[;BinFile] DltOutFile "
2211 " GenYamlCfg GENYML YamlFile YamlOutFile"
2213 " GenYamlCfg GENHDR YamlFile HdrOutFile "
2219 # Parse the options and args
2220 argc
= len(sys
.argv
)
2225 gen_cfg_data
= CGenYamlCfg()
2226 command
= sys
.argv
[1].upper()
2227 out_file
= sys
.argv
[3]
2228 if argc
>= 5 and gen_cfg_data
.parse_macros(sys
.argv
[4:]) != 0:
2229 raise Exception("ERROR: Macro parsing failed !")
2231 file_list
= sys
.argv
[2].split(';')
2232 if len(file_list
) >= 2:
2233 yml_file
= file_list
[0]
2234 dlt_file
= file_list
[1]
2235 elif len(file_list
) == 1:
2236 yml_file
= file_list
[0]
2239 raise Exception("ERROR: Invalid parameter '%s' !" % sys
.argv
[2])
2242 parts
= yml_file
.split('@')
2244 yml_scope
= parts
[1]
2246 if command
== "GENDLT" and yml_file
.endswith('.dlt'):
2247 # It needs to expand an existing DLT file
2249 lines
= gen_cfg_data
.expand_include_files(dlt_file
)
2250 write_lines(lines
, out_file
)
2253 if command
== "GENYML":
2254 if not yml_file
.lower().endswith('.yaml'):
2255 raise Exception('Only YAML file is supported !')
2256 gen_cfg_data
.generate_yml_file(yml_file
, out_file
)
2260 if (yml_file
.lower().endswith('.bin')) and (command
== "GENINC"):
2266 gen_cfg_data
.generate_data_inc_file(out_file
, bin_file
)
2272 if command
== "GENDLT":
2273 cfg_bin_file
= dlt_file
2275 if len(file_list
) >= 3:
2276 cfg_bin_file2
= file_list
[2]
2278 if yml_file
.lower().endswith('.pkl'):
2279 with
open(yml_file
, "rb") as pkl_file
:
2280 gen_cfg_data
.__dict
__ = marshal
.load(pkl_file
)
2281 gen_cfg_data
.prepare_marshal(False)
2283 # Override macro definition again for Pickle file
2285 gen_cfg_data
.parse_macros(sys
.argv
[4:])
2287 gen_cfg_data
.load_yaml(yml_file
)
2288 if command
== 'GENPKL':
2289 gen_cfg_data
.prepare_marshal(True)
2290 with
open(out_file
, "wb") as pkl_file
:
2291 marshal
.dump(gen_cfg_data
.__dict
__, pkl_file
)
2292 json_file
= os
.path
.splitext(out_file
)[0] + '.json'
2293 fo
= open(json_file
, 'w')
2295 cfgs
= {'_cfg_page': gen_cfg_data
._cfg
_page
,
2296 '_cfg_list': gen_cfg_data
._cfg
_list
,
2297 '_path_list': path_list
}
2298 # optimize to reduce size
2300 for each
in cfgs
['_cfg_list']:
2301 new_path
= each
['path'][:-len(each
['cname'])-1]
2302 if path
!= new_path
:
2305 path_list
.append(path
)
2308 if each
['order'] == each
['offset']:
2312 # value is just used to indicate display type
2313 value
= each
['value']
2314 if value
.startswith('0x'):
2315 hex_len
= ((each
['length'] + 7) // 8) * 2
2316 if len(value
) == hex_len
:
2317 value
= 'x%d' % hex_len
2320 each
['value'] = value
2321 elif value
and value
[0] in ['"', "'", '{']:
2322 each
['value'] = value
[0]
2326 fo
.write(repr(cfgs
))
2331 gen_cfg_data
.override_default_value(dlt_file
)
2333 gen_cfg_data
.detect_fsp()
2335 if command
== "GENBIN":
2336 if len(file_list
) == 3:
2337 old_data
= gen_cfg_data
.generate_binary_array()
2338 fi
= open(file_list
[2], 'rb')
2339 new_data
= bytearray(fi
.read())
2341 if len(new_data
) != len(old_data
):
2342 raise Exception("Binary file '%s' length does not match, \
2343 ignored !" % file_list
[2])
2345 gen_cfg_data
.load_default_from_bin(new_data
)
2346 gen_cfg_data
.override_default_value(dlt_file
)
2348 gen_cfg_data
.generate_binary(out_file
, yml_scope
)
2350 elif command
== "GENDLT":
2351 full
= True if 'FULL' in gen_cfg_data
._macro
_dict
else False
2352 gen_cfg_data
.generate_delta_file(out_file
, cfg_bin_file
,
2353 cfg_bin_file2
, full
)
2355 elif command
== "GENHDR":
2356 out_files
= out_file
.split(';')
2357 brd_out_file
= out_files
[0].strip()
2358 if len(out_files
) > 1:
2359 com_out_file
= out_files
[1].strip()
2362 gen_cfg_data
.create_header_file(brd_out_file
, com_out_file
, yml_scope
)
2364 elif command
== "GENINC":
2365 gen_cfg_data
.generate_data_inc_file(out_file
)
2367 elif command
== "DEBUG":
2368 gen_cfg_data
.print_cfgs()
2371 raise Exception("Unsuported command '%s' !" % command
)
2376 if __name__
== '__main__':