]>
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
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
22 # Generated file copyright header
23 __copyright_tmp__
= """/** @file
25 Platform Configuration %s File.
27 Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
28 SPDX-License-Identifier: BSD-2-Clause-Patent
30 This file is automatically generated. Please do NOT modify !!!
36 def get_copyright_header(file_type
, allow_modify
=False):
38 'yaml': 'Boot Setting',
40 'inc': 'C Binary Blob',
41 'h': 'C Struct Header'
43 if file_type
in ['yaml', 'dlt']:
47 lines
= __copyright_tmp__
.split('\n')
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
)
55 def check_quote(text
):
56 if (text
[0] == "'" and text
[-1] == "'") or (text
[0] == '"'
62 def strip_quote(text
):
63 new_text
= text
.strip()
64 if check_quote(new_text
):
69 def strip_delimiter(text
, delim
):
70 new_text
= text
.strip()
72 if new_text
[0] == delim
[0] and new_text
[-1] == delim
[-1]:
77 def bytes_to_bracket_str(bytes
):
78 return '{ %s }' % (', '.join('0x%02x' % i
for i
in bytes
))
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
)
86 for each
in val_str
.split(',')[::-1]:
88 value
= (value
<< 8) |
int(each
, 0)
92 def write_lines(lines
, file):
94 fo
.write(''.join([x
[0] for x
in lines
]))
99 if not os
.path
.exists(file):
100 test_file
= os
.path
.basename(file)
101 if os
.path
.exists(test_file
):
104 lines
= fi
.readlines()
109 def expand_file_value(path
, value_str
):
111 match
= re
.match("\\{\\s*FILE:(.+)\\}", value_str
)
113 file_list
= match
.group(1).split(',')
114 for file in file_list
:
116 bin_path
= os
.path
.join(path
, file)
117 result
.extend(bytearray(open(bin_path
, 'rb').read()))
118 print('\n\n result ', result
)
122 class ExpressionEval(ast
.NodeVisitor
):
127 ast
.Div
: op
.floordiv
,
138 ast
.Invert
: op
.invert
,
144 self
._expression
= ''
146 self
._get
_variable
= None
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
155 self
._get
_variable
= vars
156 node
= ast
.parse(self
._expression
, mode
='eval')
157 result
= self
.visit(node
.body
)
159 print('EVAL [ %s ] = %s' % (expr
, str(result
)))
162 def visit_Name(self
, node
):
163 if self
._get
_variable
is not None:
164 return self
._get
_variable
(node
.id)
166 return self
._namespace
[node
.id]
168 def visit_Num(self
, node
):
171 def visit_NameConstant(self
, node
):
174 def visit_BoolOp(self
, node
):
176 if isinstance(node
.op
, ast
.And
):
177 for value
in node
.values
:
178 result
= self
.visit(value
)
181 elif isinstance(node
.op
, ast
.Or
):
182 for value
in node
.values
:
183 result
= self
.visit(value
)
186 return True if result
else False
188 def visit_UnaryOp(self
, node
):
189 val
= self
.visit(node
.operand
)
190 return ExpressionEval
.operators
[type(node
.op
)](val
)
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
)
197 def visit_Compare(self
, node
):
198 right
= self
.visit(node
.left
)
200 for operation
, comp
in zip(node
.ops
, node
.comparators
):
204 right
= self
.visit(comp
)
205 result
= ExpressionEval
.operators
[type(operation
)](left
, right
)
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)
218 raise ValueError("Unsupported function: " + repr(node
))
220 def generic_visit(self
, node
):
221 raise ValueError("malformed node or string: " + repr(node
))
225 TEMPLATE
= 'template'
227 VARIABLE
= 'variable'
230 self
.log_line
= False
231 self
.allow_template
= False
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+(.+)')
245 def count_indent(line
):
246 return next((i
for i
, c
in enumerate(line
) if not c
.isspace()),
250 def substitue_args(text
, arg_dict
):
252 text
= text
.replace('$' + arg
, arg_dict
[arg
])
259 def process_include(self
, line
, insert
=True):
260 match
= self
.re_include
.match(line
)
262 raise Exception("Invalid !include format '%s' !" % line
.strip())
264 prefix
= match
.group(1)
265 include
= match
.group(2)
266 if prefix
.strip() == '-':
272 include
= strip_quote(include
)
273 request
= CFG_YAML
.count_indent(line
) + adjust
276 # remove the include line itself
277 del self
.full_lines
[-1]
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__
)
284 if os
.path
.exists(try_path
):
287 raise Exception("ERROR: Cannot open file '%s'." % inc_path
)
289 lines
= read_lines(inc_path
)
292 for idx
, each
in enumerate(lines
):
293 start
= each
.lstrip()
294 if start
== '' or start
[0] == '#':
298 # append the content directly at the same line
302 current
= CFG_YAML
.count_indent(each
)
305 lines
= lines
[start
+1:] if same_line
else lines
[start
:]
308 request
= len(prefix
)
311 lines
= [prefix
+ '%s\n' % leading
] + [' ' * request
+
312 i
[current
:] for i
in lines
]
314 self
.lines
= lines
+ self
.lines
318 def process_expand(self
, line
):
319 match
= self
.re_expand
.match(line
)
321 raise Exception("Invalid !expand format '%s' !" % line
.strip())
323 prefix
= match
.group(1)
324 temp_name
= match
.group(2)
325 args
= match
.group(3)
327 if prefix
.strip() == '-':
331 lines
= self
.process_expand_template(temp_name
, prefix
, args
, indent
)
332 self
.lines
= lines
+ self
.lines
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
]
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
* ' '
351 leading
= [prefix
+ '\n']
352 text
= leading
+ [(padding
+ i
+ '\n')[current
:]
353 for i
in text
.splitlines()]
356 def load_file(self
, yaml_file
):
358 self
.lines
= read_lines(yaml_file
)
361 if len(self
.lines
) == 0:
366 def put_line(self
, line
):
367 self
.lines
.insert(0, line
)
369 del self
.full_lines
[-1]
372 if len(self
.lines
) == 0:
375 line
= self
.lines
.pop(0)
377 self
.full_lines
.append(line
.rstrip())
380 def get_multiple_line(self
, indent
):
384 line
= self
.peek_line()
389 newind
= CFG_YAML
.count_indent(line
)
397 def traverse_cfg_tree(self
, handler
):
398 def _traverse_cfg_tree(root
, level
=0):
401 if type(root
[key
]) is OrderedDict
:
403 handler(key
, root
[key
], level
)
404 _traverse_cfg_tree(root
[key
], level
)
406 _traverse_cfg_tree(self
.cfg_tree
)
409 def _count(name
, cfgs
, level
):
412 self
.traverse_cfg_tree(_count
)
415 def parse(self
, parent_name
='', curr
=None, level
=0):
422 line
= self
.get_line()
426 curr_line
= line
.strip()
427 if curr_line
== '' or curr_line
[0] == '#':
430 indent
= CFG_YAML
.count_indent(line
)
431 if last_indent
is None:
434 if indent
!= last_indent
:
435 # outside of current block, put the line back to queue
436 self
.put_line(' ' * indent
+ curr_line
)
438 if curr_line
.endswith(': >'):
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
446 lines
= line
.splitlines()
447 for idx
, each
in enumerate(lines
):
448 if '!include ' in each
:
449 new_line
= ''.join(self
.process_include(each
,
451 new_lines
.append(new_line
)
453 new_lines
.append(each
)
454 self
.full_lines
= self
.full_lines
[:old_count
] + new_lines
455 curr_line
= curr_line
+ line
457 if indent
> last_indent
:
460 raise Exception('Unexpected format at line: %s'
464 self
.parse(key
, child
, level
)
466 line
= self
.peek_line()
468 curr_line
= line
.strip()
469 indent
= CFG_YAML
.count_indent(line
)
470 if indent
>= last_indent
:
480 if indent
< last_indent
:
483 marker1
= curr_line
[0]
484 marker2
= curr_line
[-1]
485 start
= 1 if marker1
== '-' else 0
486 pos
= curr_line
.find(': ')
489 key
= curr_line
[start
:pos
].strip()
490 if curr_line
[pos
+ 2] == '>':
491 curr
[key
] = curr_line
[pos
+ 3:]
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
)
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
512 child
= OrderedDict()
513 key
= curr_line
[start
:-1].strip()
515 # special virtual nodes, rename to ensure unique key
516 key
= '$ACTION_%04X' % self
.index
519 if key
not in temp_chk
:
520 # check for duplicated keys at same level
523 raise Exception("Duplicated item '%s:%s' found !"
524 % (parent_name
, key
))
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
532 for each
in self
.var_dict
:
533 txt
= self
.var_dict
[each
]
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
541 # - !include cfg_opt.yaml
542 if '!include ' in curr_line
:
543 self
.process_include(line
)
547 def load_yaml(self
, opt_file
):
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
]
556 def expand_yaml(self
, opt_file
):
558 self
.load_yaml(opt_file
)
559 self
.log_line
= False
560 text
= '\n'.join(self
.full_lines
)
565 class DefTemplate(string
.Template
):
566 idpattern
= '\\([_A-Z][_A-Z0-9]*\\)|[_A-Z][_A-Z0-9]*'
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'])
585 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'],
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
))
1059 self
.traverse_cfg_tree(_print_cfgs
)
1061 def build_var_dict(self
):
1062 def _build_var_dict(name
, cfgs
, level
):
1064 if CGenYamlCfg
.STRUCT
in cfgs
:
1065 struct_info
= cfgs
[CGenYamlCfg
.STRUCT
]
1066 self
._var
_dict
['_LENGTH_%s_' % name
] = struct_info
[
1068 self
._var
_dict
['_OFFSET_%s_' % name
] = struct_info
[
1072 self
.traverse_cfg_tree(_build_var_dict
)
1073 self
._var
_dict
['_LENGTH_'] = self
._cfg
_tree
[CGenYamlCfg
.STRUCT
][
1077 def add_cfg_page(self
, child
, parent
, title
=''):
1078 def _add_cfg_page(cfg_page
, child
, parent
):
1079 key
= next(iter(cfg_page
))
1081 cfg_page
[key
]['child'].append({child
: {'title': title
,
1086 for each
in cfg_page
[key
]['child']:
1087 if _add_cfg_page(each
, child
, parent
):
1092 return _add_cfg_page(self
._cfg
_page
, child
, parent
)
1094 def set_cur_page(self
, page_str
):
1099 page_list
= page_str
.split(',')
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()
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]
1113 if not self
.add_cfg_page(page
, parent
, parts
[2]):
1114 raise SystemExit("Error: Cannot find parent page \
1117 raise SystemExit("Error: Invalid page format '%s' !"
1119 self
._cur
_page
= page
1121 def extend_variable(self
, line
):
1122 # replace all variables
1127 line_after
= DefTemplate(line
).safe_substitute(self
._def
_dict
)
1128 if line
== line_after
:
1134 def reformat_number_per_type(self
, itype
, value
):
1135 if check_quote(value
) or value
.startswith('{'):
1137 parts
= itype
.split(',')
1138 if len(parts
) > 3 and parts
[0] == 'EditNum':
1139 num_fmt
= parts
[1].strip()
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)
1148 def add_cfg_item(self
, name
, item
, offset
, path
):
1150 self
.set_cur_page(item
.get('page', ''))
1153 # skip all virtual node
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
)))
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
)
1166 unit_len
= CGenYamlCfg
.bits_width
[match
.group(2)]
1167 length
= int(match
.group(1), 10) * unit_len
1170 length
= int(length
, 0) * 8
1172 raise Exception("Invalid length field '%s' for '%s' !" %
1173 (length
, '.'.join(path
)))
1176 raise Exception("Invalid alignment for field '%s' for \
1177 '%s' !" % (name
, '.'.join(path
)))
1179 # define is length in bytes
1182 if not name
.isidentifier():
1183 raise Exception("Invalid config name '%s' for '%s' !" %
1184 (name
, '.'.join(path
)))
1186 itype
= str(item
.get('type', 'Reserved'))
1187 value
= str(item
.get('value', ''))
1189 if not (check_quote(value
) or value
.startswith('{')):
1191 value
= '{ %s }' % value
1193 value
= self
.reformat_number_per_type(itype
, value
)
1195 help = str(item
.get('help', ''))
1197 help = ' '.join([i
.strip() for i
in help.splitlines()])
1199 option
= str(item
.get('option', ''))
1201 option
= ' '.join([i
.strip() for i
in option
.splitlines()])
1203 # extend variables for value and condition
1204 condition
= str(item
.get('condition', ''))
1206 condition
= self
.extend_variable(condition
)
1207 value
= self
.extend_variable(value
)
1209 order
= str(item
.get('order', ''))
1212 (major
, minor
) = order
.split('.')
1213 order
= int(major
, 16)
1215 order
= int(order
, 16)
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
)
1236 item
['indx'] = len(self
._cfg
_list
) - 1
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)
1247 def build_cfg_list(self
, cfg_name
='', top
=None, path
=[],
1248 info
={'offset': 0}):
1250 top
= self
._cfg
_tree
1252 info
= {'offset': 0}
1254 start
= info
['offset']
1258 if type(top
[key
]) is OrderedDict
:
1260 self
.build_cfg_list(key
, top
[key
], path
, info
)
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)
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 !" %
1282 def get_field_value(self
, top
=None):
1283 def _get_field_value(name
, cfgs
, level
):
1285 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1286 if act_cfg
['length'] == 0:
1288 value
= self
.get_value(act_cfg
['value'], act_cfg
['length'],
1290 set_bits_to_bytes(result
, act_cfg
['offset'] -
1291 struct_info
['offset'], act_cfg
['length'],
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
)
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
:
1305 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1306 actual_offset
= act_cfg
['offset'] - struct_info
['offset']
1308 for each
in self
.bin_offset
:
1309 if actual_offset
in range(each
[0], (each
[0] + each
[2]) * 8):
1312 if set_value
and force
or act_cfg
['value'] == '':
1313 value
= get_bits_from_bytes(full_bytes
,
1316 act_val
= act_cfg
['value']
1318 act_val
= '%d' % value
1319 act_val
= self
.reformat_number_per_type(act_cfg
1322 act_cfg
['value'] = self
.format_value_to_str(
1323 value
, act_cfg
['length'], act_val
)
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'])
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
)
1340 def update_def_value(self
):
1341 def _update_def_value(name
, cfgs
, level
):
1343 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1344 if act_cfg
['value'] != '' and act_cfg
['length'] > 0:
1346 act_cfg
['value'] = self
.reformat_value_str(
1347 act_cfg
['value'], act_cfg
['length'])
1349 raise Exception("Invalid value expression '%s' \
1350 for '%s' !" % (act_cfg
['value'], act_cfg
['path']))
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
)
1359 self
.traverse_cfg_tree(_update_def_value
, self
._cfg
_tree
)
1361 def evaluate_condition(self
, item
):
1362 expr
= item
['condition']
1363 result
= self
.parse_value(expr
, 1, False)
1366 def detect_fsp(self
):
1367 cfg_segs
= self
.get_cfg_segment()
1368 if len(cfg_segs
) == 3:
1370 for idx
, seg
in enumerate(cfg_segs
):
1371 if not seg
[0].endswith('UPD_%s' % 'TMS'[idx
]):
1377 self
.set_mode('FSP')
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_'):
1385 find
[0] = cfgs
['find']
1388 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1389 segments
.append([find
[0], act_cfg
['offset'] // 8, 0])
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
])
1400 segments
.append(['', cfg_len
, 0])
1402 for idx
, each
in enumerate(segments
[:-1]):
1403 cfg_segs
.append((each
[0], each
[1],
1404 segments
[idx
+1][1] - each
[1]))
1408 def get_bin_segment(self
, bin_data
):
1409 cfg_segs
= self
.get_cfg_segment()
1411 for seg
in cfg_segs
:
1412 key
= seg
[0].encode()
1414 bin_segs
.append([seg
[0], 0, len(bin_data
)])
1416 pos
= bin_data
.find(key
)
1418 # ensure no other match for the key
1419 next_pos
= bin_data
.find(key
, pos
+ len(seg
[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
)
1429 print("Warning: Multiple matches for '%s' "
1430 "in binary, the 1st instance will be used !"
1432 bin_segs
.append([seg
[0], pos
, seg
[2]])
1433 self
.binseg_dict
[seg
[0]] = pos
1435 bin_segs
.append([seg
[0], -1, seg
[2]])
1436 self
.binseg_dict
[seg
[0]] = -1
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
)
1446 for each
in bin_segs
:
1448 self
.bin_offset
.append([Dummy_offset
, each
[1], each
[2]])
1449 cfg_bins
.extend(bin_data
[each
[1]:each
[1] + each
[2]])
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]
1458 def save_current_to_bin(self
):
1459 cfg_bins
= self
.generate_binary_array()
1460 if self
._old
_bin
is None:
1463 bin_data
= bytearray(self
._old
_bin
)
1464 bin_segs
= self
.get_bin_segment(self
._old
_bin
)
1466 for each
in bin_segs
:
1469 bin_data
[each
[1]:each
[1] + length
] = cfg_bins
[cfg_off
:
1476 print('Patched the loaded binary successfully !')
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)
1485 def generate_binary_array(self
, path
=''):
1489 top
= self
.locate_cfg_item(path
)
1491 raise Exception("Invalid configuration path '%s' !"
1494 return self
.get_field_value(top
)
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
))
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:
1507 dlt_fd
.write('# Delta configuration values for '
1508 'platform ID 0x%04X\n'
1510 dlt_fd
.write('#\n\n')
1511 for line
in out_lines
:
1512 dlt_fd
.write('%s\n' % line
)
1515 def override_default_value(self
, dlt_file
):
1517 dlt_lines
= CGenYamlCfg
.expand_include_files(dlt_file
)
1520 for line
, file_path
, line_num
in dlt_lines
:
1522 if not line
or line
.startswith('#'):
1524 match
= re
.match("\\s*([\\w\\.]+)\\s*\\|\\s*(.+)", line
)
1526 raise Exception("Unrecognized line '%s' "
1527 "(File:'%s' Line:%d) !"
1528 % (line
, file_path
, line_num
+ 1))
1530 path
= match
.group(1)
1531 value_str
= match
.group(2)
1532 top
= self
.locate_cfg_item(path
)
1535 "Invalid configuration '%s' (File:'%s' Line:%d) !" %
1536 (path
, file_path
, line_num
+ 1))
1539 act_cfg
= self
.get_item_by_index(top
['indx'])
1540 bit_len
= act_cfg
['length']
1542 struct_info
= top
[CGenYamlCfg
.STRUCT
]
1543 bit_len
= struct_info
['length']
1545 value_bytes
= self
.parse_value(value_str
, bit_len
)
1546 self
.set_field_value(top
, value_bytes
, True)
1548 if path
== 'PLATFORMID_CFG_DATA.PlatformId':
1549 platform_id
= value_str
1551 if platform_id
is None:
1553 "PLATFORMID_CFG_DATA.PlatformId is missing "
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
)
1566 for item
in self
._cfg
_list
:
1567 if not full
and (item
['type'] in ['Reserved']):
1569 old_val
= get_bits_from_bytes(old_data
, item
['offset'],
1571 new_val
= get_bits_from_bytes(new_data
, item
['offset'],
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'],
1580 text
= '%-40s | %s' % (full_name
, val_str
)
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
)
1589 lines
.insert(0, '%-40s | %s\n\n' %
1590 ('PLATFORMID_CFG_DATA.PlatformId',
1591 '0x%04X' % platform_id
))
1595 self
.write_delta_file(delta_file
, platform_id
, lines
)
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()))
1605 old_data
= self
.generate_binary_array()
1608 fd
= open(bin_file2
, 'rb')
1609 new_data
= self
.extract_cfg_from_bin(bytearray(fd
.read()))
1612 return self
.generate_delta_file_from_bin(delta_file
,
1613 old_data
, new_data
, full
)
1615 def prepare_marshal(self
, is_save
):
1617 # Ordered dict is not marshallable, convert to list
1618 self
._cfg
_tree
= CGenYamlCfg
.deep_convert_dict(self
._cfg
_tree
)
1621 self
._cfg
_tree
= CGenYamlCfg
.deep_convert_list(self
._cfg
_tree
)
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")
1631 def write_cfg_header_file(self
, hdr_file_name
, tag_mode
,
1632 tag_dict
, struct_list
):
1634 lines
.append('\n\n')
1635 if self
.get_mode() == 'FSP':
1636 lines
.append('#include <FspUpd.h>\n')
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):
1644 lines
.append('#define %-30s 0x%03X\n' % (
1645 'CDATA_%s_TAG' % tagname
[:-9], tagval
))
1646 lines
.append('\n\n')
1650 for each
in struct_list
:
1651 if (tag_mode
== 0 and each
['tag'] >= 0x100) or \
1652 (tag_mode
== 1 and each
['tag'] < 0x100):
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')
1661 self
.write_header_file(lines
, hdr_file_name
)
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()
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
)
1674 lines
.append("#pragma pack(1)\n\n")
1675 lines
.extend(txt_body
)
1677 lines
.append("#pragma pack()\n\n")
1678 lines
.append("#endif\n")
1680 # Don't rewrite if the contents are the same
1682 if os
.path
.exists(file_name
):
1683 hdr_file
= open(file_name
, "r")
1684 org_txt
= hdr_file
.read()
1687 new_txt
= ''.join(lines
)
1688 if org_txt
== new_txt
:
1692 hdr_file
= open(file_name
, "w")
1693 hdr_file
.write(''.join(lines
))
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'
1701 fin
= open(bin_file
, 'rb')
1702 bin_dat
= prefix
+ bytearray(fin
.read())
1705 bin_dat
= prefix
+ self
.generate_binary_array()
1707 file_name
= os
.path
.basename(dat_inc_file_name
).upper()
1708 file_name
= file_name
.replace('.', '_')
1712 txt_lines
.append("UINT8 mConfigDataBlob[%d] = {\n" % len(bin_dat
))
1715 for each
in bin_dat
:
1716 line
.append('0x%02X, ' % each
)
1718 if (count
& 0x0F) == 0:
1720 txt_lines
.append(''.join(line
))
1723 txt_lines
.append(''.join(line
) + '\n')
1725 txt_lines
.append("};\n\n")
1726 self
.write_header_file(txt_lines
, dat_inc_file_name
, 'inc')
1730 def get_struct_array_info(self
, input):
1731 parts
= input.split(':')
1737 array_str
= input.split('[')
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
)
1745 return name
, array_num
, var
1747 def process_multilines(self
, string
, max_char_length
):
1749 string_length
= len(string
)
1750 current_string_start
= 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)
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()
1769 multilines
= " %s\n" % string
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
1781 new_line_start
= new_line_start
+ new_line_count
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
1794 if break_line_dict
!= []:
1795 break_line_dict
.sort()
1796 for each
in break_line_dict
:
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()
1806 def create_field(self
, item
, name
, length
, offset
, struct
,
1807 bsf_name
, help, option
, bits_length
=None):
1813 if length
== 0 and name
== 'dummy':
1816 if bits_length
== 0:
1820 if length
in [1, 2, 4, 8]:
1821 type = "UINT%d" % (length
* 8)
1826 if item
and item
['value'].startswith('{'):
1831 struct_base
= struct
.rstrip('*')
1832 name
= '*' * (len(struct
) - len(struct_base
)) + name
1833 struct
= struct_base
1835 if struct
in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
1837 unit
= int(type[4:]) // 8
1838 length
= length
/ unit
1843 name
= name
+ '[%d]' % length
1845 if len(type) < pos_name
:
1846 space1
= pos_name
- len(type)
1851 name_line
= " %s\n" % bsf_name
1856 # help_line = self.process_multilines(help, 80)
1859 # option_line = self.process_multilines(option, 80)
1864 offset_str
= '0x%04X' % offset
1866 if bits_length
is None:
1869 bits_length
= ' : %d' % bits_length
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
,
1877 def create_struct(self
, cname
, top
, struct_dict
):
1883 if cname
in struct_dict
:
1884 if struct_dict
[cname
][2]:
1886 lines
.append('\ntypedef struct {\n')
1894 if 'indx' not in t_item
:
1895 if CGenYamlCfg
.STRUCT
not in top
[field
]:
1898 if struct_dict
[field
][1] == 0:
1902 struct_info
= top
[field
][CGenYamlCfg
.STRUCT
]
1904 if 'struct' in struct_info
:
1905 struct
, array_num
, var
= self
.get_struct_array_info(
1906 struct_info
['struct'])
1914 field
= CGenYamlCfg
.format_struct_field_name(
1915 var
, struct_dict
[field
][1])
1917 struct
= struct_dict
[field
][0]
1918 field
= CGenYamlCfg
.format_struct_field_name(
1919 field
, struct_dict
[field
][1])
1922 offset
= t_item
['$STRUCT']['offset'] // 8
1925 line
= self
.create_field(None, field
, 0, 0, struct
,
1927 lines
.append(' %s' % line
)
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):
1937 length
= (item
['length'] + 7) // 8
1938 match
= re
.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)",
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
1946 offset
= item
['offset'] // 8
1949 struct
= item
.get('struct', '')
1951 prompt
= item
['name']
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
)
1959 lines
.append('\n} %s;\n\n' % cname
)
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")
1971 for fsp_comp
in 'TMS':
1972 top
= self
.locate_cfg_item('FSP%s_UPD' % fsp_comp
)
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]),
1980 hdr_fd
.write(''.join(lines
))
1981 hdr_fd
.write("#pragma pack()\n\n"
1985 def create_header_file(self
, hdr_file_name
, com_hdr_file_name
='', path
=''):
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
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
)
2007 top
= self
.locate_cfg_item(path
)
2009 raise Exception("Invalid configuration path '%s' !" % path
)
2010 _build_header_struct(path
, top
, 0)
2011 self
.traverse_cfg_tree(_build_header_struct
, top
)
2013 if tag_curr
[0] == 0:
2018 if re
.match('FSP[TMS]_UPD', path
):
2021 # filter out the items to be built for tags and structures
2023 for each
in struct_dict
:
2025 for check
in CGenYamlCfg
.exclude_struct
:
2026 if re
.match(check
, each
):
2028 if each
in tag_dict
:
2029 if each
not in CGenYamlCfg
.include_tag
:
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]})
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'],
2043 # Convert XXX_[0-9]+ to XXX as an array hint
2044 for each
in struct_list
:
2046 if 'struct' in cfgs
['$STRUCT']:
2047 each
['alias'], array_num
, var
= self
.get_struct_array_info(
2048 cfgs
['$STRUCT']['struct'])
2050 match
= re
.match('(\\w+)(_\\d+)', each
['name'])
2052 each
['alias'] = match
.group(1)
2054 each
['alias'] = each
['name']
2056 # count items for array build
2057 for idx
, each
in enumerate(struct_list
):
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
2072 # generate common header
2073 if com_hdr_file_name
:
2074 self
.write_cfg_header_file(com_hdr_file_name
, 0, tag_dict
,
2077 # generate platform header
2078 self
.write_cfg_header_file(hdr_file_name
, hdr_mode
, tag_dict
,
2083 def load_yaml(self
, cfg_file
):
2084 cfg_yaml
= CFG_YAML()
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()
2097 "GenYamlCfg Version 0.50",
2099 " GenYamlCfg GENINC BinFile IncOutFile "
2102 " GenYamlCfg GENPKL YamlFile PklOutFile "
2104 " GenYamlCfg GENBIN YamlFile[;DltFile] BinOutFile "
2106 " GenYamlCfg GENDLT YamlFile[;BinFile] DltOutFile "
2108 " GenYamlCfg GENYML YamlFile YamlOutFile"
2110 " GenYamlCfg GENHDR YamlFile HdrOutFile "
2116 # Parse the options and args
2117 argc
= len(sys
.argv
)
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 !")
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]
2136 raise Exception("ERROR: Invalid parameter '%s' !" % sys
.argv
[2])
2139 parts
= yml_file
.split('@')
2141 yml_scope
= parts
[1]
2143 if command
== "GENDLT" and yml_file
.endswith('.dlt'):
2144 # It needs to expand an existing DLT file
2146 lines
= gen_cfg_data
.expand_include_files(dlt_file
)
2147 write_lines(lines
, out_file
)
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
)
2157 if (yml_file
.lower().endswith('.bin')) and (command
== "GENINC"):
2163 gen_cfg_data
.generate_data_inc_file(out_file
, bin_file
)
2169 if command
== "GENDLT":
2170 cfg_bin_file
= dlt_file
2172 if len(file_list
) >= 3:
2173 cfg_bin_file2
= file_list
[2]
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)
2180 # Override macro definition again for Pickle file
2182 gen_cfg_data
.parse_macros(sys
.argv
[4:])
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')
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
2197 for each
in cfgs
['_cfg_list']:
2198 new_path
= each
['path'][:-len(each
['cname'])-1]
2199 if path
!= new_path
:
2202 path_list
.append(path
)
2205 if each
['order'] == each
['offset']:
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
2217 each
['value'] = value
2218 elif value
and value
[0] in ['"', "'", '{']:
2219 each
['value'] = value
[0]
2223 fo
.write(repr(cfgs
))
2228 gen_cfg_data
.override_default_value(dlt_file
)
2230 gen_cfg_data
.detect_fsp()
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())
2238 if len(new_data
) != len(old_data
):
2239 raise Exception("Binary file '%s' length does not match, \
2240 ignored !" % file_list
[2])
2242 gen_cfg_data
.load_default_from_bin(new_data
)
2243 gen_cfg_data
.override_default_value(dlt_file
)
2245 gen_cfg_data
.generate_binary(out_file
, yml_scope
)
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
)
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()
2259 gen_cfg_data
.create_header_file(brd_out_file
, com_out_file
, yml_scope
)
2261 elif command
== "GENINC":
2262 gen_cfg_data
.generate_data_inc_file(out_file
)
2264 elif command
== "DEBUG":
2265 gen_cfg_data
.print_cfgs()
2268 raise Exception("Unsuported command '%s' !" % command
)
2273 if __name__
== '__main__':