]>
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
= {}
588 def initialize(self
):
593 self
._cfg
_page
= {'root': {'title': '', 'child': []}}
600 def deep_convert_dict(layer
):
601 # convert OrderedDict to list + dict
603 if isinstance(layer
, OrderedDict
):
604 new_list
= list(layer
.items())
605 for idx
, pair
in enumerate(new_list
):
606 new_node
= CGenYamlCfg
.deep_convert_dict(pair
[1])
607 new_list
[idx
] = dict({pair
[0]: new_node
})
611 def deep_convert_list(layer
):
612 if isinstance(layer
, list):
615 if isinstance(each
, dict):
616 key
= next(iter(each
))
617 od
[key
] = CGenYamlCfg
.deep_convert_list(each
[key
])
623 def expand_include_files(file_path
, cur_dir
=''):
625 cur_dir
= os
.path
.dirname(file_path
)
626 file_path
= os
.path
.basename(file_path
)
628 input_file_path
= os
.path
.join(cur_dir
, file_path
)
629 file = open(input_file_path
, "r")
630 lines
= file.readlines()
633 for line_num
, line
in enumerate(lines
):
634 match
= re
.match("^!include\\s*(.+)?$", line
.strip())
636 inc_path
= match
.group(1)
637 tmp_path
= os
.path
.join(cur_dir
, inc_path
)
639 if not os
.path
.exists(tmp_path
):
640 cur_dir
= os
.path
.join(os
.path
.dirname
641 (os
.path
.realpath(__file__
)
643 tmp_path
= os
.path
.join(cur_dir
, inc_path
)
644 if not os
.path
.exists(tmp_path
):
645 raise Exception("ERROR: Cannot open include\
646 file '%s'." % org_path
)
648 new_lines
.append(('# Included from file: %s\n' % inc_path
,
650 new_lines
.append(('# %s\n' % ('=' * 80), tmp_path
, 0))
651 new_lines
.extend(CGenYamlCfg
.expand_include_files
654 new_lines
.append((line
, input_file_path
, line_num
))
659 def format_struct_field_name(input, count
=0):
663 input = input.lower()
674 name
= '%s[%d]' % (name
, count
)
681 def set_mode(self
, mode
):
684 def get_last_error(self
):
687 def get_variable(self
, var
, attr
='value'):
688 if var
in self
._var
_dict
:
689 var
= self
._var
_dict
[var
]
692 item
= self
.locate_cfg_item(var
, False)
694 raise ValueError("Cannot find variable '%s' !" % var
)
698 item
= self
.get_item_by_index(item
['indx'])
701 elif attr
== 'length':
703 elif attr
== 'value':
704 var
= self
.get_cfg_item_value(item
)
706 raise ValueError("Unsupported variable attribute '%s' !" %
710 def eval(self
, expr
):
711 def _handler(pattern
):
716 result
= self
.get_variable(pattern
.group(target
))
718 raise ValueError('Unknown variable $(%s) !' %
719 pattern
.group(target
))
722 expr_eval
= ExpressionEval()
724 # replace known variable first
725 expr
= re
.sub(r
'\$\(([_a-zA-Z][\w\.]*)\)|\$([_a-zA-Z][\w\.]*)',
727 return expr_eval
.eval(expr
, self
.get_variable
)
729 def parse_macros(self
, macro_def_str
):
730 # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']
731 self
._macro
_dict
= {}
732 is_expression
= False
733 for macro
in macro_def_str
:
734 if macro
.startswith('-D'):
741 is_expression
= False
742 match
= re
.match("(\\w+)=(.+)", macro
)
744 self
._macro
_dict
[match
.group(1)] = match
.group(2)
746 match
= re
.match("(\\w+)", macro
)
748 self
._macro
_dict
[match
.group(1)] = ''
749 if len(self
._macro
_dict
) == 0:
754 print("INFO : Macro dictionary:")
755 for each
in self
._macro
_dict
:
756 print(" $(%s) = [ %s ]"
757 % (each
, self
._macro
_dict
[each
]))
760 def get_cfg_list(self
, page_id
=None):
763 return self
._cfg
_list
765 # build a new list for items under a page ID
766 cfgs
= [i
for i
in self
._cfg
_list
if i
['cname'] and
767 (i
['page'] == page_id
)]
770 def get_cfg_page(self
):
771 return self
._cfg
_page
773 def get_cfg_item_length(self
, item
):
774 return item
['length']
776 def get_cfg_item_value(self
, item
, array
=False):
777 value_str
= item
['value']
778 length
= item
['length']
779 return self
.get_value(value_str
, length
, array
)
781 def format_value_to_str(self
, value
, bit_length
, old_value
=''):
782 # value is always int
783 length
= (bit_length
+ 7) // 8
785 if old_value
.startswith('0x'):
787 elif old_value
and (old_value
[0] in ['"', "'", '{']):
792 bvalue
= value_to_bytearray(value
, length
)
793 if fmt
in ['"', "'"]:
794 svalue
= bvalue
.rstrip(b
'\x00').decode()
795 value_str
= fmt
+ svalue
+ fmt
797 value_str
= '{ ' + ', '.join(['0x%02x' % i
for i
in bvalue
]) + ' }'
800 if len(old_value
) == hex_len
+ 2:
801 fstr
= '0x%%0%dx' % hex_len
804 value_str
= fstr
% value
807 value_str
= '%d' % value
809 value_str
= '0x%x' % value
811 value_str
= '{ ' + ', '.join(['0x%02x' % i
for i
in
815 def reformat_value_str(self
, value_str
, bit_length
, old_value
=None):
816 value
= self
.parse_value(value_str
, bit_length
, False)
817 if old_value
is None:
818 old_value
= value_str
819 new_value
= self
.format_value_to_str(value
, bit_length
, old_value
)
822 def get_value(self
, value_str
, bit_length
, array
=True):
823 value_str
= value_str
.strip()
824 if value_str
[0] == "'" and value_str
[-1] == "'" or \
825 value_str
[0] == '"' and value_str
[-1] == '"':
826 value_str
= value_str
[1:-1]
827 bvalue
= bytearray(value_str
.encode())
829 bvalue
= bytearray(b
'\x00')
833 return bytes_to_value(bvalue
)
835 if value_str
[0] in '{':
836 value_str
= value_str
[1:-1].strip()
838 for each
in value_str
.split(',')[::-1]:
840 value
= (value
<< 8) |
int(each
, 0)
842 length
= (bit_length
+ 7) // 8
843 return value_to_bytearray(value
, length
)
847 def parse_value(self
, value_str
, bit_length
, array
=True):
848 length
= (bit_length
+ 7) // 8
849 if check_quote(value_str
):
850 value_str
= bytes_to_bracket_str(value_str
[1:-1].encode())
851 elif (',' in value_str
) and (value_str
[0] != '{'):
852 value_str
= '{ %s }' % value_str
853 if value_str
[0] == '{':
854 result
= expand_file_value(self
._yaml
_path
, value_str
)
856 bin_list
= value_str
[1:-1].split(',')
860 for idx
, element
in enumerate(bin_list
):
861 each
= element
.strip()
866 if each
[0] in "'" + '"':
867 each_value
= bytearray(each
[1:-1], 'utf-8')
869 match
= re
.match("^(.+):(\\d+)([b|B|W|D|Q])$", each
)
871 raise SystemExit("Exception: Invald value\
872 list format '%s' !" % each
)
873 if match
.group(1) == '0' and match
.group(2) == '0':
874 unit_len
= CGenYamlCfg
.bits_width
[match
.group(3)
876 cur_bit_len
= int(match
.group(2)
877 ) * CGenYamlCfg
.bits_width
[
879 value
+= ((self
.eval(match
.group(1)) & (
880 1 << cur_bit_len
) - 1)) << bit_len
881 bit_len
+= cur_bit_len
882 each_value
= bytearray()
883 if idx
+ 1 < len(bin_list
):
887 each_value
= value_to_bytearray(
888 self
.eval(each
.strip()), unit_len
)
890 raise SystemExit("Exception: Value %d cannot \
891 fit into %s bytes !" % (each
, unit_len
))
896 raise SystemExit("Exception: Invalid bit \
897 field alignment '%s' !" % value_str
)
898 result
.extend(value_to_bytes(value
, bit_len
// 8))
902 result
.extend(each_value
)
904 elif check_quote(value_str
):
905 result
= bytearray(value_str
[1:-1], 'utf-8') # Excluding quotes
907 result
= value_to_bytearray(self
.eval(value_str
), length
)
909 if len(result
) < length
:
910 result
.extend(b
'\x00' * (length
- len(result
)))
911 elif len(result
) > length
:
912 raise SystemExit("Exception: Value '%s' is too big to fit \
913 into %d bytes !" % (value_str
, length
))
918 return bytes_to_value(result
)
922 def get_cfg_item_options(self
, item
):
924 if item
['type'] == "Combo":
925 if item
['option'] in CGenYamlCfg
.builtin_option
:
926 for op_val
, op_str
in CGenYamlCfg
.builtin_option
[item
['option'
928 tmp_list
.append((op_val
, op_str
))
930 opt_list
= item
['option'].split(',')
931 for option
in opt_list
:
932 option
= option
.strip()
934 (op_val
, op_str
) = option
.split(':')
936 raise SystemExit("Exception: Invalide \
937 option format '%s' !" % option
)
938 tmp_list
.append((op_val
, op_str
))
941 def get_page_title(self
, page_id
, top
=None):
943 top
= self
.get_cfg_page()['root']
944 for node
in top
['child']:
945 page_key
= next(iter(node
))
946 if page_id
== page_key
:
947 return node
[page_key
]['title']
949 result
= self
.get_page_title(page_id
, node
[page_key
])
950 if result
is not None:
954 def print_pages(self
, top
=None, level
=0):
956 top
= self
.get_cfg_page()['root']
957 for node
in top
['child']:
958 page_id
= next(iter(node
))
959 print('%s%s: %s' % (' ' * level
, page_id
, node
[page_id
]['title']))
961 self
.print_pages(node
[page_id
], level
)
964 def get_item_by_index(self
, index
):
965 return self
._cfg
_list
[index
]
967 def get_item_by_path(self
, path
):
968 node
= self
.locate_cfg_item(path
)
970 return self
.get_item_by_index(node
['indx'])
974 def locate_cfg_path(self
, item
):
975 def _locate_cfg_path(root
, level
=0):
980 if type(root
[key
]) is OrderedDict
:
983 ret
= _locate_cfg_path(root
[key
], level
)
989 return _locate_cfg_path(self
._cfg
_tree
)
991 def locate_cfg_item(self
, path
, allow_exp
=True):
992 def _locate_cfg_item(root
, path
, level
=0):
993 if len(path
) == level
:
995 next_root
= root
.get(path
[level
], None)
996 if next_root
is None:
998 raise Exception('Not a valid CFG config option path: %s' %
999 '.'.join(path
[:level
+1]))
1002 return _locate_cfg_item(next_root
, path
, level
+ 1)
1004 path_nodes
= path
.split('.')
1005 return _locate_cfg_item(self
._cfg
_tree
, path_nodes
)
1007 def traverse_cfg_tree(self
, handler
, top
=None):
1008 def _traverse_cfg_tree(root
, level
=0):
1011 if type(root
[key
]) is OrderedDict
:
1013 handler(key
, root
[key
], level
)
1014 _traverse_cfg_tree(root
[key
], level
)
1018 top
= self
._cfg
_tree
1019 _traverse_cfg_tree(top
)
1021 def print_cfgs(self
, root
=None, short
=True, print_level
=256):
1022 def _print_cfgs(name
, cfgs
, level
):
1025 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1030 if CGenYamlCfg
.STRUCT
in cfgs
:
1031 cfg
= cfgs
[CGenYamlCfg
.STRUCT
]
1032 offset
= int(cfg
['offset'])
1033 length
= int(cfg
['length'])
1035 value
= cfg
['value']
1038 act_cfg
= dict({'value': value
, 'offset': offset
,
1040 value
= act_cfg
['value']
1041 bit_len
= act_cfg
['length']
1042 offset
= (act_cfg
['offset'] + 7) // 8
1045 value
= self
.reformat_value_str(act_cfg
['value'],
1048 value
= act_cfg
['value']
1049 length
= bit_len
// 8
1050 bit_len
= '(%db)' % bit_len
if bit_len
% 8 else '' * 4
1051 if level
<= print_level
:
1052 if short
and len(value
) > 40:
1053 value
= '%s ... %s' % (value
[:20], value
[-20:])
1054 print('%04X:%04X%-6s %s%s : %s' % (offset
, length
, bit_len
,
1055 ' ' * level
, name
, value
))
1057 self
.traverse_cfg_tree(_print_cfgs
)
1059 def build_var_dict(self
):
1060 def _build_var_dict(name
, cfgs
, level
):
1062 if CGenYamlCfg
.STRUCT
in cfgs
:
1063 struct_info
= cfgs
[CGenYamlCfg
.STRUCT
]
1064 self
._var
_dict
['_LENGTH_%s_' % name
] = struct_info
[
1066 self
._var
_dict
['_OFFSET_%s_' % name
] = struct_info
[
1070 self
.traverse_cfg_tree(_build_var_dict
)
1071 self
._var
_dict
['_LENGTH_'] = self
._cfg
_tree
[CGenYamlCfg
.STRUCT
][
1075 def add_cfg_page(self
, child
, parent
, title
=''):
1076 def _add_cfg_page(cfg_page
, child
, parent
):
1077 key
= next(iter(cfg_page
))
1079 cfg_page
[key
]['child'].append({child
: {'title': title
,
1084 for each
in cfg_page
[key
]['child']:
1085 if _add_cfg_page(each
, child
, parent
):
1090 return _add_cfg_page(self
._cfg
_page
, child
, parent
)
1092 def set_cur_page(self
, page_str
):
1097 page_list
= page_str
.split(',')
1099 page_list
= [page_str
]
1100 for page_str
in page_list
:
1101 parts
= page_str
.split(':')
1102 if len(parts
) in [1, 3]:
1103 page
= parts
[0].strip()
1105 # it is a new page definition, add it into tree
1106 parent
= parts
[1] if parts
[1] else 'root'
1107 parent
= parent
.strip()
1108 if parts
[2][0] == '"' and parts
[2][-1] == '"':
1109 parts
[2] = parts
[2][1:-1]
1111 if not self
.add_cfg_page(page
, parent
, parts
[2]):
1112 raise SystemExit("Error: Cannot find parent page \
1115 raise SystemExit("Error: Invalid page format '%s' !"
1117 self
._cur
_page
= page
1119 def extend_variable(self
, line
):
1120 # replace all variables
1125 line_after
= DefTemplate(line
).safe_substitute(self
._def
_dict
)
1126 if line
== line_after
:
1132 def reformat_number_per_type(self
, itype
, value
):
1133 if check_quote(value
) or value
.startswith('{'):
1135 parts
= itype
.split(',')
1136 if len(parts
) > 3 and parts
[0] == 'EditNum':
1137 num_fmt
= parts
[1].strip()
1140 if num_fmt
== 'HEX' and not value
.startswith('0x'):
1141 value
= '0x%X' % int(value
, 10)
1142 elif num_fmt
== 'DEC' and value
.startswith('0x'):
1143 value
= '%d' % int(value
, 16)
1146 def add_cfg_item(self
, name
, item
, offset
, path
):
1148 self
.set_cur_page(item
.get('page', ''))
1151 # skip all virtual node
1154 if not set(item
).issubset(CGenYamlCfg
.keyword_set
):
1155 for each
in list(item
):
1156 if each
not in CGenYamlCfg
.keyword_set
:
1157 raise Exception("Invalid attribute '%s' for '%s'!" %
1158 (each
, '.'.join(path
)))
1160 length
= item
.get('length', 0)
1161 if type(length
) is str:
1162 match
= re
.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)\\s*$", length
)
1164 unit_len
= CGenYamlCfg
.bits_width
[match
.group(2)]
1165 length
= int(match
.group(1), 10) * unit_len
1168 length
= int(length
, 0) * 8
1170 raise Exception("Invalid length field '%s' for '%s' !" %
1171 (length
, '.'.join(path
)))
1174 raise Exception("Invalid alignment for field '%s' for \
1175 '%s' !" % (name
, '.'.join(path
)))
1177 # define is length in bytes
1180 if not name
.isidentifier():
1181 raise Exception("Invalid config name '%s' for '%s' !" %
1182 (name
, '.'.join(path
)))
1184 itype
= str(item
.get('type', 'Reserved'))
1185 value
= str(item
.get('value', ''))
1187 if not (check_quote(value
) or value
.startswith('{')):
1189 value
= '{ %s }' % value
1191 value
= self
.reformat_number_per_type(itype
, value
)
1193 help = str(item
.get('help', ''))
1195 help = ' '.join([i
.strip() for i
in help.splitlines()])
1197 option
= str(item
.get('option', ''))
1199 option
= ' '.join([i
.strip() for i
in option
.splitlines()])
1201 # extend variables for value and condition
1202 condition
= str(item
.get('condition', ''))
1204 condition
= self
.extend_variable(condition
)
1205 value
= self
.extend_variable(value
)
1207 order
= str(item
.get('order', ''))
1210 (major
, minor
) = order
.split('.')
1211 order
= int(major
, 16)
1213 order
= int(order
, 16)
1218 cfg_item
['length'] = length
1219 cfg_item
['offset'] = offset
1220 cfg_item
['value'] = value
1221 cfg_item
['type'] = itype
1222 cfg_item
['cname'] = str(name
)
1223 cfg_item
['name'] = str(item
.get('name', ''))
1224 cfg_item
['help'] = help
1225 cfg_item
['option'] = option
1226 cfg_item
['page'] = self
._cur
_page
1227 cfg_item
['order'] = order
1228 cfg_item
['path'] = '.'.join(path
)
1229 cfg_item
['condition'] = condition
1230 if 'struct' in item
:
1231 cfg_item
['struct'] = item
['struct']
1232 self
._cfg
_list
.append(cfg_item
)
1234 item
['indx'] = len(self
._cfg
_list
) - 1
1236 # remove used info for reducing pkl size
1237 item
.pop('option', None)
1238 item
.pop('condition', None)
1239 item
.pop('help', None)
1240 item
.pop('name', None)
1241 item
.pop('page', None)
1245 def build_cfg_list(self
, cfg_name
='', top
=None, path
=[],
1246 info
={'offset': 0}):
1248 top
= self
._cfg
_tree
1250 info
= {'offset': 0}
1252 start
= info
['offset']
1256 if type(top
[key
]) is OrderedDict
:
1258 self
.build_cfg_list(key
, top
[key
], path
, info
)
1262 length
= self
.add_cfg_item(cfg_name
, top
, info
['offset'], path
)
1263 info
['offset'] += length
1264 elif cfg_name
== '' or (cfg_name
and cfg_name
[0] != '$'):
1265 # check first element for struct
1266 first
= next(iter(top
))
1267 struct_str
= CGenYamlCfg
.STRUCT
1268 if first
!= struct_str
:
1269 struct_node
= OrderedDict({})
1270 top
[struct_str
] = struct_node
1271 top
.move_to_end(struct_str
, False)
1273 struct_node
= top
[struct_str
]
1274 struct_node
['offset'] = start
1275 struct_node
['length'] = info
['offset'] - start
1276 if struct_node
['length'] % 8 != 0:
1277 raise SystemExit("Error: Bits length not aligned for %s !" %
1280 def get_field_value(self
, top
=None):
1281 def _get_field_value(name
, cfgs
, level
):
1283 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1284 if act_cfg
['length'] == 0:
1286 value
= self
.get_value(act_cfg
['value'], act_cfg
['length'],
1288 set_bits_to_bytes(result
, act_cfg
['offset'] -
1289 struct_info
['offset'], act_cfg
['length'],
1293 top
= self
._cfg
_tree
1294 struct_info
= top
[CGenYamlCfg
.STRUCT
]
1295 result
= bytearray((struct_info
['length'] + 7) // 8)
1296 self
.traverse_cfg_tree(_get_field_value
, top
)
1299 def set_field_value(self
, top
, value_bytes
, force
=False):
1300 def _set_field_value(name
, cfgs
, level
):
1301 if 'indx' not in cfgs
:
1303 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1304 if force
or act_cfg
['value'] == '':
1305 value
= get_bits_from_bytes(full_bytes
,
1307 struct_info
['offset'],
1309 act_val
= act_cfg
['value']
1311 act_val
= '%d' % value
1312 act_val
= self
.reformat_number_per_type(act_cfg
1315 act_cfg
['value'] = self
.format_value_to_str(
1316 value
, act_cfg
['length'], act_val
)
1319 # it is config option
1320 value
= bytes_to_value(value_bytes
)
1321 act_cfg
= self
.get_item_by_index(top
['indx'])
1322 act_cfg
['value'] = self
.format_value_to_str(
1323 value
, act_cfg
['length'], act_cfg
['value'])
1326 struct_info
= top
[CGenYamlCfg
.STRUCT
]
1327 length
= struct_info
['length'] // 8
1328 full_bytes
= bytearray(value_bytes
[:length
])
1329 if len(full_bytes
) < length
:
1330 full_bytes
.extend(bytearray(length
- len(value_bytes
)))
1331 self
.traverse_cfg_tree(_set_field_value
, top
)
1333 def update_def_value(self
):
1334 def _update_def_value(name
, cfgs
, level
):
1336 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1337 if act_cfg
['value'] != '' and act_cfg
['length'] > 0:
1339 act_cfg
['value'] = self
.reformat_value_str(
1340 act_cfg
['value'], act_cfg
['length'])
1342 raise Exception("Invalid value expression '%s' \
1343 for '%s' !" % (act_cfg
['value'], act_cfg
['path']))
1345 if CGenYamlCfg
.STRUCT
in cfgs
and 'value' in \
1346 cfgs
[CGenYamlCfg
.STRUCT
]:
1347 curr
= cfgs
[CGenYamlCfg
.STRUCT
]
1348 value_bytes
= self
.get_value(curr
['value'],
1349 curr
['length'], True)
1350 self
.set_field_value(cfgs
, value_bytes
)
1352 self
.traverse_cfg_tree(_update_def_value
, self
._cfg
_tree
)
1354 def evaluate_condition(self
, item
):
1355 expr
= item
['condition']
1356 result
= self
.parse_value(expr
, 1, False)
1359 def detect_fsp(self
):
1360 cfg_segs
= self
.get_cfg_segment()
1361 if len(cfg_segs
) == 3:
1363 for idx
, seg
in enumerate(cfg_segs
):
1364 if not seg
[0].endswith('UPD_%s' % 'TMS'[idx
]):
1370 self
.set_mode('FSP')
1373 def get_cfg_segment(self
):
1374 def _get_cfg_segment(name
, cfgs
, level
):
1375 if 'indx' not in cfgs
:
1376 if name
.startswith('$ACTION_'):
1378 find
[0] = cfgs
['find']
1381 act_cfg
= self
.get_item_by_index(cfgs
['indx'])
1382 segments
.append([find
[0], act_cfg
['offset'] // 8, 0])
1388 self
.traverse_cfg_tree(_get_cfg_segment
, self
._cfg
_tree
)
1389 cfg_len
= self
._cfg
_tree
[CGenYamlCfg
.STRUCT
]['length'] // 8
1390 if len(segments
) == 0:
1391 segments
.append(['', 0, cfg_len
])
1393 segments
.append(['', cfg_len
, 0])
1395 for idx
, each
in enumerate(segments
[:-1]):
1396 cfg_segs
.append((each
[0], each
[1],
1397 segments
[idx
+1][1] - each
[1]))
1401 def get_bin_segment(self
, bin_data
):
1402 cfg_segs
= self
.get_cfg_segment()
1404 for seg
in cfg_segs
:
1405 key
= seg
[0].encode()
1407 bin_segs
.append([seg
[0], 0, len(bin_data
)])
1409 pos
= bin_data
.find(key
)
1411 # ensure no other match for the key
1412 next_pos
= bin_data
.find(key
, pos
+ len(seg
[0]))
1414 if key
== b
'$SKLFSP$' or key
== b
'$BSWFSP$':
1415 string
= ('Warning: Multiple matches for %s in '
1416 'binary!\n\nA workaround applied to such '
1417 'FSP 1.x binary to use second'
1418 ' match instead of first match!' % key
)
1419 messagebox
.showwarning('Warning!', string
)
1422 print("Warning: Multiple matches for '%s' "
1423 "in binary, the 1st instance will be used !"
1425 bin_segs
.append([seg
[0], pos
, seg
[2]])
1427 raise Exception("Could not find '%s' in binary !"
1432 def extract_cfg_from_bin(self
, bin_data
):
1433 # get cfg bin length
1434 cfg_bins
= bytearray()
1435 bin_segs
= self
.get_bin_segment(bin_data
)
1436 for each
in bin_segs
:
1437 cfg_bins
.extend(bin_data
[each
[1]:each
[1] + each
[2]])
1440 def save_current_to_bin(self
):
1441 cfg_bins
= self
.generate_binary_array()
1442 if self
._old
_bin
is None:
1445 bin_data
= bytearray(self
._old
_bin
)
1446 bin_segs
= self
.get_bin_segment(self
._old
_bin
)
1448 for each
in bin_segs
:
1450 bin_data
[each
[1]:each
[1] + length
] = cfg_bins
[cfg_off
:
1454 print('Patched the loaded binary successfully !')
1458 def load_default_from_bin(self
, bin_data
):
1459 self
._old
_bin
= bin_data
1460 cfg_bins
= self
.extract_cfg_from_bin(bin_data
)
1461 self
.set_field_value(self
._cfg
_tree
, cfg_bins
, True)
1464 def generate_binary_array(self
, path
=''):
1468 top
= self
.locate_cfg_item(path
)
1470 raise Exception("Invalid configuration path '%s' !"
1472 return self
.get_field_value(top
)
1474 def generate_binary(self
, bin_file_name
, path
=''):
1475 bin_file
= open(bin_file_name
, "wb")
1476 bin_file
.write(self
.generate_binary_array(path
))
1480 def write_delta_file(self
, out_file
, platform_id
, out_lines
):
1481 dlt_fd
= open(out_file
, "w")
1482 dlt_fd
.write("%s\n" % get_copyright_header('dlt', True))
1483 if platform_id
is not None:
1485 dlt_fd
.write('# Delta configuration values for '
1486 'platform ID 0x%04X\n'
1488 dlt_fd
.write('#\n\n')
1489 for line
in out_lines
:
1490 dlt_fd
.write('%s\n' % line
)
1493 def override_default_value(self
, dlt_file
):
1495 dlt_lines
= CGenYamlCfg
.expand_include_files(dlt_file
)
1498 for line
, file_path
, line_num
in dlt_lines
:
1500 if not line
or line
.startswith('#'):
1502 match
= re
.match("\\s*([\\w\\.]+)\\s*\\|\\s*(.+)", line
)
1504 raise Exception("Unrecognized line '%s' "
1505 "(File:'%s' Line:%d) !"
1506 % (line
, file_path
, line_num
+ 1))
1508 path
= match
.group(1)
1509 value_str
= match
.group(2)
1510 top
= self
.locate_cfg_item(path
)
1513 "Invalid configuration '%s' (File:'%s' Line:%d) !" %
1514 (path
, file_path
, line_num
+ 1))
1517 act_cfg
= self
.get_item_by_index(top
['indx'])
1518 bit_len
= act_cfg
['length']
1520 struct_info
= top
[CGenYamlCfg
.STRUCT
]
1521 bit_len
= struct_info
['length']
1523 value_bytes
= self
.parse_value(value_str
, bit_len
)
1524 self
.set_field_value(top
, value_bytes
, True)
1526 if path
== 'PLATFORMID_CFG_DATA.PlatformId':
1527 platform_id
= value_str
1529 if platform_id
is None:
1531 "PLATFORMID_CFG_DATA.PlatformId is missing "
1537 def generate_delta_file_from_bin(self
, delta_file
, old_data
,
1538 new_data
, full
=False):
1539 new_data
= self
.load_default_from_bin(new_data
)
1544 for item
in self
._cfg
_list
:
1545 if not full
and (item
['type'] in ['Reserved']):
1547 old_val
= get_bits_from_bytes(old_data
, item
['offset'],
1549 new_val
= get_bits_from_bytes(new_data
, item
['offset'],
1552 full_name
= item
['path']
1553 if 'PLATFORMID_CFG_DATA.PlatformId' == full_name
:
1554 def_platform_id
= old_val
1555 if new_val
!= old_val
or full
:
1556 val_str
= self
.reformat_value_str(item
['value'],
1558 text
= '%-40s | %s' % (full_name
, val_str
)
1561 if self
.get_mode() != 'FSP':
1562 if platform_id
is None or def_platform_id
== platform_id
:
1563 platform_id
= def_platform_id
1564 print("WARNING: 'PlatformId' configuration is "
1565 "same as default %d!" % platform_id
)
1567 lines
.insert(0, '%-40s | %s\n\n' %
1568 ('PLATFORMID_CFG_DATA.PlatformId',
1569 '0x%04X' % platform_id
))
1573 self
.write_delta_file(delta_file
, platform_id
, lines
)
1577 def generate_delta_file(self
, delta_file
, bin_file
, bin_file2
, full
=False):
1578 fd
= open(bin_file
, 'rb')
1579 new_data
= self
.extract_cfg_from_bin(bytearray(fd
.read()))
1583 old_data
= self
.generate_binary_array()
1586 fd
= open(bin_file2
, 'rb')
1587 new_data
= self
.extract_cfg_from_bin(bytearray(fd
.read()))
1590 return self
.generate_delta_file_from_bin(delta_file
,
1591 old_data
, new_data
, full
)
1593 def prepare_marshal(self
, is_save
):
1595 # Ordered dict is not marshallable, convert to list
1596 self
._cfg
_tree
= CGenYamlCfg
.deep_convert_dict(self
._cfg
_tree
)
1599 self
._cfg
_tree
= CGenYamlCfg
.deep_convert_list(self
._cfg
_tree
)
1601 def generate_yml_file(self
, in_file
, out_file
):
1602 cfg_yaml
= CFG_YAML()
1603 text
= cfg_yaml
.expand_yaml(in_file
)
1604 yml_fd
= open(out_file
, "w")
1609 def write_cfg_header_file(self
, hdr_file_name
, tag_mode
,
1610 tag_dict
, struct_list
):
1612 lines
.append('\n\n')
1613 if self
.get_mode() == 'FSP':
1614 lines
.append('#include <FspUpd.h>\n')
1616 tag_mode
= tag_mode
& 0x7F
1617 tag_list
= sorted(list(tag_dict
.items()), key
=lambda x
: x
[1])
1618 for tagname
, tagval
in tag_list
:
1619 if (tag_mode
== 0 and tagval
>= 0x100) or \
1620 (tag_mode
== 1 and tagval
< 0x100):
1622 lines
.append('#define %-30s 0x%03X\n' % (
1623 'CDATA_%s_TAG' % tagname
[:-9], tagval
))
1624 lines
.append('\n\n')
1628 for each
in struct_list
:
1629 if (tag_mode
== 0 and each
['tag'] >= 0x100) or \
1630 (tag_mode
== 1 and each
['tag'] < 0x100):
1632 new_dict
[each
['name']] = (each
['alias'], each
['count'])
1633 if each
['alias'] not in name_dict
:
1634 name_dict
[each
['alias']] = 1
1635 lines
.extend(self
.create_struct(each
['alias'],
1636 each
['node'], new_dict
))
1637 lines
.append('#pragma pack()\n\n')
1639 self
.write_header_file(lines
, hdr_file_name
)
1641 def write_header_file(self
, txt_body
, file_name
, type='h'):
1642 file_name_def
= os
.path
.basename(file_name
).replace('.', '_')
1643 file_name_def
= re
.sub('(.)([A-Z][a-z]+)', r
'\1_\2', file_name_def
)
1644 file_name_def
= re
.sub('([a-z0-9])([A-Z])', r
'\1_\2',
1645 file_name_def
).upper()
1648 lines
.append("%s\n" % get_copyright_header(type))
1649 lines
.append("#ifndef __%s__\n" % file_name_def
)
1650 lines
.append("#define __%s__\n\n" % file_name_def
)
1652 lines
.append("#pragma pack(1)\n\n")
1653 lines
.extend(txt_body
)
1655 lines
.append("#pragma pack()\n\n")
1656 lines
.append("#endif\n")
1658 # Don't rewrite if the contents are the same
1660 if os
.path
.exists(file_name
):
1661 hdr_file
= open(file_name
, "r")
1662 org_txt
= hdr_file
.read()
1665 new_txt
= ''.join(lines
)
1666 if org_txt
== new_txt
:
1670 hdr_file
= open(file_name
, "w")
1671 hdr_file
.write(''.join(lines
))
1674 def generate_data_inc_file(self
, dat_inc_file_name
, bin_file
=None):
1675 # Put a prefix GUID before CFGDATA so that it can be located later on
1676 prefix
= b
'\xa7\xbd\x7f\x73\x20\x1e\x46\xd6\
1677 xbe\x8f\x64\x12\x05\x8d\x0a\xa8'
1679 fin
= open(bin_file
, 'rb')
1680 bin_dat
= prefix
+ bytearray(fin
.read())
1683 bin_dat
= prefix
+ self
.generate_binary_array()
1685 file_name
= os
.path
.basename(dat_inc_file_name
).upper()
1686 file_name
= file_name
.replace('.', '_')
1690 txt_lines
.append("UINT8 mConfigDataBlob[%d] = {\n" % len(bin_dat
))
1693 for each
in bin_dat
:
1694 line
.append('0x%02X, ' % each
)
1696 if (count
& 0x0F) == 0:
1698 txt_lines
.append(''.join(line
))
1701 txt_lines
.append(''.join(line
) + '\n')
1703 txt_lines
.append("};\n\n")
1704 self
.write_header_file(txt_lines
, dat_inc_file_name
, 'inc')
1708 def get_struct_array_info(self
, input):
1709 parts
= input.split(':')
1715 array_str
= input.split('[')
1717 if len(array_str
) > 1:
1718 num_str
= ''.join(c
for c
in array_str
[-1] if c
.isdigit())
1719 num_str
= '1000' if len(num_str
) == 0 else num_str
1720 array_num
= int(num_str
)
1723 return name
, array_num
, var
1725 def process_multilines(self
, string
, max_char_length
):
1727 string_length
= len(string
)
1728 current_string_start
= 0
1730 break_line_dict
= []
1731 if len(string
) <= max_char_length
:
1732 while (string_offset
< string_length
):
1733 if string_offset
>= 1:
1734 if string
[string_offset
- 1] == '\\' and string
[
1735 string_offset
] == 'n':
1736 break_line_dict
.append(string_offset
+ 1)
1738 if break_line_dict
!= []:
1739 for each
in break_line_dict
:
1740 multilines
+= " %s\n" % string
[
1741 current_string_start
:each
].lstrip()
1742 current_string_start
= each
1743 if string_length
- current_string_start
> 0:
1744 multilines
+= " %s\n" % string
[
1745 current_string_start
:].lstrip()
1747 multilines
= " %s\n" % string
1751 found_space_char
= False
1752 while (string_offset
< string_length
):
1753 if string_offset
>= 1:
1754 if new_line_count
>= max_char_length
- 1:
1755 if string
[string_offset
] == ' ' and \
1756 string_length
- string_offset
> 10:
1757 break_line_dict
.append(new_line_start
1759 new_line_start
= new_line_start
+ new_line_count
1761 found_space_char
= True
1762 elif string_offset
== string_length
- 1 and \
1763 found_space_char
is False:
1764 break_line_dict
.append(0)
1765 if string
[string_offset
- 1] == '\\' and string
[
1766 string_offset
] == 'n':
1767 break_line_dict
.append(string_offset
+ 1)
1768 new_line_start
= string_offset
+ 1
1772 if break_line_dict
!= []:
1773 break_line_dict
.sort()
1774 for each
in break_line_dict
:
1776 multilines
+= " %s\n" % string
[
1777 current_string_start
:each
].lstrip()
1778 current_string_start
= each
1779 if string_length
- current_string_start
> 0:
1780 multilines
+= " %s\n" % \
1781 string
[current_string_start
:].lstrip()
1784 def create_field(self
, item
, name
, length
, offset
, struct
,
1785 bsf_name
, help, option
, bits_length
=None):
1791 if length
== 0 and name
== 'dummy':
1794 if bits_length
== 0:
1798 if length
in [1, 2, 4, 8]:
1799 type = "UINT%d" % (length
* 8)
1804 if item
and item
['value'].startswith('{'):
1809 struct_base
= struct
.rstrip('*')
1810 name
= '*' * (len(struct
) - len(struct_base
)) + name
1811 struct
= struct_base
1813 if struct
in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
1815 unit
= int(type[4:]) // 8
1816 length
= length
/ unit
1821 name
= name
+ '[%d]' % length
1823 if len(type) < pos_name
:
1824 space1
= pos_name
- len(type)
1829 name_line
= " %s\n" % bsf_name
1834 # help_line = self.process_multilines(help, 80)
1837 # option_line = self.process_multilines(option, 80)
1842 offset_str
= '0x%04X' % offset
1844 if bits_length
is None:
1847 bits_length
= ' : %d' % bits_length
1849 # return "\n/** %s%s%s**/\n %s%s%s%s;\n" % (name_line, help_line,
1850 # option_line, type, ' ' * space1, name, bits_length)
1851 return "\n /* Offset %s: %s */\n %s%s%s%s;\n" % (
1852 offset_str
, name_line
.strip(), type, ' ' * space1
,
1855 def create_struct(self
, cname
, top
, struct_dict
):
1861 if cname
in struct_dict
:
1862 if struct_dict
[cname
][2]:
1864 lines
.append('\ntypedef struct {\n')
1872 if 'indx' not in t_item
:
1873 if CGenYamlCfg
.STRUCT
not in top
[field
]:
1876 if struct_dict
[field
][1] == 0:
1880 struct_info
= top
[field
][CGenYamlCfg
.STRUCT
]
1882 if 'struct' in struct_info
:
1883 struct
, array_num
, var
= self
.get_struct_array_info(
1884 struct_info
['struct'])
1892 field
= CGenYamlCfg
.format_struct_field_name(
1893 var
, struct_dict
[field
][1])
1895 struct
= struct_dict
[field
][0]
1896 field
= CGenYamlCfg
.format_struct_field_name(
1897 field
, struct_dict
[field
][1])
1900 offset
= t_item
['$STRUCT']['offset'] // 8
1903 line
= self
.create_field(None, field
, 0, 0, struct
,
1905 lines
.append(' %s' % line
)
1909 item
= self
.get_item_by_index(t_item
['indx'])
1910 if item
['cname'] == 'CfgHeader' and index
== 1 or \
1911 (item
['cname'] == 'CondValue' and index
== 2):
1915 length
= (item
['length'] + 7) // 8
1916 match
= re
.match("^(\\d+)([b|B|W|D|Q])([B|W|D|Q]?)",
1918 if match
and match
.group(2) == 'b':
1919 bit_length
= int(match
.group(1))
1920 if match
.group(3) != '':
1921 length
= CGenYamlCfg
.bits_width
[match
.group(3)] // 8
1924 offset
= item
['offset'] // 8
1927 struct
= item
.get('struct', '')
1929 prompt
= item
['name']
1931 option
= item
['option']
1932 line
= self
.create_field(item
, name
, length
, offset
, struct
,
1933 prompt
, help, option
, bit_length
)
1934 lines
.append(' %s' % line
)
1937 lines
.append('\n} %s;\n\n' % cname
)
1941 def write_fsp_sig_header_file(self
, hdr_file_name
):
1942 hdr_fd
= open(hdr_file_name
, 'w')
1943 hdr_fd
.write("%s\n" % get_copyright_header('h'))
1944 hdr_fd
.write("#ifndef __FSPUPD_H__\n"
1945 "#define __FSPUPD_H__\n\n"
1946 "#include <FspEas.h>\n\n"
1947 "#pragma pack(1)\n\n")
1949 for fsp_comp
in 'TMS':
1950 top
= self
.locate_cfg_item('FSP%s_UPD' % fsp_comp
)
1952 raise Exception('Could not find FSP UPD definition !')
1953 bins
= self
.get_field_value(top
)
1954 lines
.append("#define FSP%s_UPD_SIGNATURE"
1955 " 0x%016X /* '%s' */\n\n"
1956 % (fsp_comp
, bytes_to_value(bins
[:8]),
1958 hdr_fd
.write(''.join(lines
))
1959 hdr_fd
.write("#pragma pack()\n\n"
1963 def create_header_file(self
, hdr_file_name
, com_hdr_file_name
='', path
=''):
1965 def _build_header_struct(name
, cfgs
, level
):
1966 if CGenYamlCfg
.STRUCT
in cfgs
:
1967 if 'CfgHeader' in cfgs
:
1968 # collect CFGDATA TAG IDs
1969 cfghdr
= self
.get_item_by_index(cfgs
['CfgHeader']['indx'])
1970 tag_val
= array_str_to_value(cfghdr
['value']) >> 20
1971 tag_dict
[name
] = tag_val
1973 tag_curr
[0] = tag_val
1974 struct_dict
[name
] = (level
, tag_curr
[0], cfgs
)
1975 if path
== 'FSP_SIG':
1976 self
.write_fsp_sig_header_file(hdr_file_name
)
1985 top
= self
.locate_cfg_item(path
)
1987 raise Exception("Invalid configuration path '%s' !" % path
)
1988 _build_header_struct(path
, top
, 0)
1989 self
.traverse_cfg_tree(_build_header_struct
, top
)
1991 if tag_curr
[0] == 0:
1996 if re
.match('FSP[TMS]_UPD', path
):
1999 # filter out the items to be built for tags and structures
2001 for each
in struct_dict
:
2003 for check
in CGenYamlCfg
.exclude_struct
:
2004 if re
.match(check
, each
):
2006 if each
in tag_dict
:
2007 if each
not in CGenYamlCfg
.include_tag
:
2011 struct_list
.append({'name': each
, 'alias': '', 'count': 0,
2012 'level': struct_dict
[each
][0],
2013 'tag': struct_dict
[each
][1],
2014 'node': struct_dict
[each
][2]})
2016 # sort by level so that the bottom level struct
2017 # will be build first to satisfy dependencies
2018 struct_list
= sorted(struct_list
, key
=lambda x
: x
['level'],
2021 # Convert XXX_[0-9]+ to XXX as an array hint
2022 for each
in struct_list
:
2024 if 'struct' in cfgs
['$STRUCT']:
2025 each
['alias'], array_num
, var
= self
.get_struct_array_info(
2026 cfgs
['$STRUCT']['struct'])
2028 match
= re
.match('(\\w+)(_\\d+)', each
['name'])
2030 each
['alias'] = match
.group(1)
2032 each
['alias'] = each
['name']
2034 # count items for array build
2035 for idx
, each
in enumerate(struct_list
):
2037 last_struct
= struct_list
[idx
-1]['node']['$STRUCT']
2038 curr_struct
= each
['node']['$STRUCT']
2039 if struct_list
[idx
-1]['alias'] == each
['alias'] and \
2040 curr_struct
['length'] == last_struct
['length'] and \
2041 curr_struct
['offset'] == last_struct
['offset'] + \
2042 last_struct
['length']:
2043 for idx2
in range(idx
-1, -1, -1):
2044 if struct_list
[idx2
]['count'] > 0:
2045 struct_list
[idx2
]['count'] += 1
2050 # generate common header
2051 if com_hdr_file_name
:
2052 self
.write_cfg_header_file(com_hdr_file_name
, 0, tag_dict
,
2055 # generate platform header
2056 self
.write_cfg_header_file(hdr_file_name
, hdr_mode
, tag_dict
,
2061 def load_yaml(self
, cfg_file
):
2062 cfg_yaml
= CFG_YAML()
2064 self
._cfg
_tree
= cfg_yaml
.load_yaml(cfg_file
)
2065 self
._def
_dict
= cfg_yaml
.def_dict
2066 self
._yaml
_path
= os
.path
.dirname(cfg_file
)
2067 self
.build_cfg_list()
2068 self
.build_var_dict()
2069 self
.update_def_value()
2075 "GenYamlCfg Version 0.50",
2077 " GenYamlCfg GENINC BinFile IncOutFile "
2080 " GenYamlCfg GENPKL YamlFile PklOutFile "
2082 " GenYamlCfg GENBIN YamlFile[;DltFile] BinOutFile "
2084 " GenYamlCfg GENDLT YamlFile[;BinFile] DltOutFile "
2086 " GenYamlCfg GENYML YamlFile YamlOutFile"
2088 " GenYamlCfg GENHDR YamlFile HdrOutFile "
2094 # Parse the options and args
2095 argc
= len(sys
.argv
)
2100 gen_cfg_data
= CGenYamlCfg()
2101 command
= sys
.argv
[1].upper()
2102 out_file
= sys
.argv
[3]
2103 if argc
>= 5 and gen_cfg_data
.parse_macros(sys
.argv
[4:]) != 0:
2104 raise Exception("ERROR: Macro parsing failed !")
2106 file_list
= sys
.argv
[2].split(';')
2107 if len(file_list
) >= 2:
2108 yml_file
= file_list
[0]
2109 dlt_file
= file_list
[1]
2110 elif len(file_list
) == 1:
2111 yml_file
= file_list
[0]
2114 raise Exception("ERROR: Invalid parameter '%s' !" % sys
.argv
[2])
2117 parts
= yml_file
.split('@')
2119 yml_scope
= parts
[1]
2121 if command
== "GENDLT" and yml_file
.endswith('.dlt'):
2122 # It needs to expand an existing DLT file
2124 lines
= gen_cfg_data
.expand_include_files(dlt_file
)
2125 write_lines(lines
, out_file
)
2128 if command
== "GENYML":
2129 if not yml_file
.lower().endswith('.yaml'):
2130 raise Exception('Only YAML file is supported !')
2131 gen_cfg_data
.generate_yml_file(yml_file
, out_file
)
2135 if (yml_file
.lower().endswith('.bin')) and (command
== "GENINC"):
2141 gen_cfg_data
.generate_data_inc_file(out_file
, bin_file
)
2147 if command
== "GENDLT":
2148 cfg_bin_file
= dlt_file
2150 if len(file_list
) >= 3:
2151 cfg_bin_file2
= file_list
[2]
2153 if yml_file
.lower().endswith('.pkl'):
2154 with
open(yml_file
, "rb") as pkl_file
:
2155 gen_cfg_data
.__dict
__ = marshal
.load(pkl_file
)
2156 gen_cfg_data
.prepare_marshal(False)
2158 # Override macro definition again for Pickle file
2160 gen_cfg_data
.parse_macros(sys
.argv
[4:])
2162 gen_cfg_data
.load_yaml(yml_file
)
2163 if command
== 'GENPKL':
2164 gen_cfg_data
.prepare_marshal(True)
2165 with
open(out_file
, "wb") as pkl_file
:
2166 marshal
.dump(gen_cfg_data
.__dict
__, pkl_file
)
2167 json_file
= os
.path
.splitext(out_file
)[0] + '.json'
2168 fo
= open(json_file
, 'w')
2170 cfgs
= {'_cfg_page': gen_cfg_data
._cfg
_page
,
2171 '_cfg_list': gen_cfg_data
._cfg
_list
,
2172 '_path_list': path_list
}
2173 # optimize to reduce size
2175 for each
in cfgs
['_cfg_list']:
2176 new_path
= each
['path'][:-len(each
['cname'])-1]
2177 if path
!= new_path
:
2180 path_list
.append(path
)
2183 if each
['order'] == each
['offset']:
2187 # value is just used to indicate display type
2188 value
= each
['value']
2189 if value
.startswith('0x'):
2190 hex_len
= ((each
['length'] + 7) // 8) * 2
2191 if len(value
) == hex_len
:
2192 value
= 'x%d' % hex_len
2195 each
['value'] = value
2196 elif value
and value
[0] in ['"', "'", '{']:
2197 each
['value'] = value
[0]
2201 fo
.write(repr(cfgs
))
2206 gen_cfg_data
.override_default_value(dlt_file
)
2208 gen_cfg_data
.detect_fsp()
2210 if command
== "GENBIN":
2211 if len(file_list
) == 3:
2212 old_data
= gen_cfg_data
.generate_binary_array()
2213 fi
= open(file_list
[2], 'rb')
2214 new_data
= bytearray(fi
.read())
2216 if len(new_data
) != len(old_data
):
2217 raise Exception("Binary file '%s' length does not match, \
2218 ignored !" % file_list
[2])
2220 gen_cfg_data
.load_default_from_bin(new_data
)
2221 gen_cfg_data
.override_default_value(dlt_file
)
2223 gen_cfg_data
.generate_binary(out_file
, yml_scope
)
2225 elif command
== "GENDLT":
2226 full
= True if 'FULL' in gen_cfg_data
._macro
_dict
else False
2227 gen_cfg_data
.generate_delta_file(out_file
, cfg_bin_file
,
2228 cfg_bin_file2
, full
)
2230 elif command
== "GENHDR":
2231 out_files
= out_file
.split(';')
2232 brd_out_file
= out_files
[0].strip()
2233 if len(out_files
) > 1:
2234 com_out_file
= out_files
[1].strip()
2237 gen_cfg_data
.create_header_file(brd_out_file
, com_out_file
, yml_scope
)
2239 elif command
== "GENINC":
2240 gen_cfg_data
.generate_data_inc_file(out_file
)
2242 elif command
== "DEBUG":
2243 gen_cfg_data
.print_cfgs()
2246 raise Exception("Unsuported command '%s' !" % command
)
2251 if __name__
== '__main__':