]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Scripts/ConvertFceToStructurePcd.py
3 # Firmware Configuration Editor (FCE) from https://firmware.intel.com/develop
4 # can parse BIOS image and generate Firmware Configuration file.
5 # This script bases on Firmware Configuration file, and generate the structure
6 # PCD setting in DEC/DSC/INF files.
8 # Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
9 # SPDX-License-Identifier: BSD-2-Clause-Patent
13 ConvertFceToStructurePcd
22 # Globals for help information
24 __prog__
= 'ConvertFceToStructurePcd'
25 __version__
= '%s Version %s' % (__prog__
, '0.1 ')
26 __copyright__
= 'Copyright (c) 2018, Intel Corporation. All rights reserved.'
27 __description__
= 'Generate Structure PCD in DEC/DSC/INF based on Firmware Configuration.\n'
30 dscstatement
='''[Defines]
31 VPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E08
34 0|DEFAULT # The entry: 0|DEFAULT is reserved and always required.
37 0|STANDARD # UEFI Standard default 0|STANDARD is reserved.
38 1|MANUFACTURING # UEFI Manufacturing default 1|MANUFACTURING is reserved.
40 [PcdsDynamicExVpd.common.DEFAULT]
41 gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer|*
44 decstatement
= '''[Guids]
45 gStructPcdTokenSpaceGuid = {0x3f1406f4, 0x2b, 0x487a, {0x8b, 0x69, 0x74, 0x29, 0x1b, 0x36, 0x16, 0xf4}}
47 [PcdsFixedAtBuild,PcdsPatchableInModule,PcdsDynamic,PcdsDynamicEx]
50 infstatement
= '''[Pcd]
53 SECTION
='PcdsDynamicHii'
54 PCD_NAME
='gStructPcdTokenSpaceGuid.Pcd'
59 class parser_lst(object):
61 def __init__(self
,filelist
):
62 self
._ignore
=['BOOLEAN', 'UINT8', 'UINT16', 'UINT32', 'UINT64']
64 self
.text
=self
.megre_lst()[0]
65 self
.content
=self
.megre_lst()[1]
70 for file in self
.file:
71 with
open(file,'r') as f
:
75 return alltext
,content
77 def struct_lst(self
):#{struct:lst file}
79 name_format
= re
.compile(r
'(?<!typedef)\s+struct (\w+) {.*?;', re
.S
)
80 for i
in list(self
.content
.keys()):
81 structs
= name_format
.findall(self
.content
[i
])
84 if j
not in self
._ignore
:
90 def struct(self
):#struct:{offset:name}
91 unit_num
= re
.compile('(\d+)')
92 offset1_re
= re
.compile('(\d+)\[')
93 pcdname_num_re
= re
.compile('\w+\[(\S+)\]')
94 pcdname_re
= re
.compile('\](.*)\<')
95 pcdname2_re
= re
.compile('(\w+)\[')
96 uint_re
= re
.compile('\<(\S+)\>')
97 name_format
= re
.compile(r
'(?<!typedef)\s+struct (\w+) {.*?;', re
.S
)
98 name
=name_format
.findall(self
.text
)
102 tmp_n
= [n
for n
in name
if n
not in self
._ignore
]
103 name
= list(set(tmp_n
))
104 name
.sort(key
= tmp_n
.index
)
106 #name=list(set(name).difference(set(self._ignore)))
108 s_re
= re
.compile(r
'struct %s :(.*?)};'% struct
, re
.S
)
109 content
= s_re
.search(self
.text
)
112 text
= content
.group().split('+')
113 for line
in text
[1:]:
114 offset
= offset1_re
.findall(line
)
115 t_name
= pcdname_re
.findall(line
)
116 uint
= uint_re
.findall(line
)
121 t_name
= t_name
[0].strip()
122 if (' ' in t_name
) or ("=" in t_name
) or (";" in t_name
) or("\\" in name
) or (t_name
==''):
123 WARNING
.append("Warning:Invalid Pcd name '%s' for Offset %s in struct %s" % (t_name
,offset
, struct
))
126 if uint
in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
127 offset
= int(offset
, 10)
128 tmp_name
= pcdname2_re
.findall(t_name
)[0] + '[0]'
129 tmp_dict
[offset
] = tmp_name
130 pcdname_num
= int(pcdname_num_re
.findall(t_name
)[0],10)
131 uint
= int(unit_num
.findall(uint
)[0],10)
133 for i
in range(1, pcdname_num
):
135 tmp_name
= pcdname2_re
.findall(t_name
)[0] + '[%s]' % i
136 tmp_dict
[offset
] = tmp_name
138 tmp_name
= pcdname2_re
.findall(t_name
)[0]
139 pcdname_num
= pcdname_num_re
.findall(t_name
)[0]
140 line
= [offset
,tmp_name
,pcdname_num
,uint
]
144 if uint
not in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
145 line
= [offset
, t_name
, 0, uint
]
149 offset
= int(offset
,10)
150 tmp_dict
[offset
] = t_name
151 info
[struct
] = tmp_dict
152 if len(unparse
) != 0:
154 if u
[3] in list(info
.keys()):
155 unpar
= self
.nameISstruct(u
,info
[u
[3]])
156 info
[u
[4]]= dict(list(info
[u
[4]].items())+list(unpar
[u
[4]].items()))
158 print("ERROR: No struct name found in %s" % self
.file)
159 ERRORMSG
.append("ERROR: No struct name found in %s" % self
.file)
163 def nameISstruct(self
,line
,key_dict
):
166 s_re
= re
.compile(r
'struct %s :(.*?)};' % line
[3], re
.S
)
167 size_re
= re
.compile(r
'mTotalSize \[(\S+)\]')
168 content
= s_re
.search(self
.text
)
170 s_size
= size_re
.findall(content
.group())[0]
173 print("ERROR: Struct %s not define mTotalSize in lst file" %line
[3])
174 ERRORMSG
.append("ERROR: Struct %s not define mTotalSize in lst file" %line
[3])
175 size
= int(line
[0], 10)
177 for j
in range(0, int(line
[2], 10)):
178 for k
in list(key_dict
.keys()):
180 name
='%s.%s' %((line
[1]+'[%s]'%j
),key_dict
[k
])
182 size
= int(s_size
,16)+size
184 for k
in list(key_dict
.keys()):
186 name
= '%s.%s' % (line
[1], key_dict
[k
])
188 dict2
[line
[4]] = dict
191 def efivarstore_parser(self
):
192 efivarstore_format
= re
.compile(r
'efivarstore.*?;', re
.S
)
193 struct_re
= re
.compile(r
'efivarstore(.*?),',re
.S
)
194 name_re
= re
.compile(r
'name=(\w+)')
196 efitxt
= efivarstore_format
.findall(self
.text
)
198 struct
= struct_re
.findall(i
.replace(' ',''))
199 name
= name_re
.findall(i
.replace(' ',''))
201 efivarstore_dict
[name
[0]]=struct
[0]
203 print("ERROR: Can't find Struct or name in lst file, please check have this format:efivarstore XXXX, name=xxxx")
204 ERRORMSG
.append("ERROR: Can't find Struct or name in lst file, please check have this format:efivarstore XXXX, name=xxxx")
205 return efivarstore_dict
207 class Config(object):
209 def __init__(self
,Config
):
212 #Parser .config file,return list[offset,name,guid,value,help]
213 def config_parser(self
):
214 ids_re
=re
.compile('_ID:(\d+)',re
.S
)
215 id_re
= re
.compile('\s+')
218 with
open(self
.config
, 'r') as text
:
220 if 'DEFAULT_ID:' in read
:
221 all_txt
= read
.split('FCEKEY DEFAULT')
222 for i
in all_txt
[1:]:
223 part
= [] #save all infomation for DEFAULT_ID
225 ids
= ids_re
.findall(i
.replace(' ',''))
230 section
= i
.split('\nQ') #split with '\nQ ' to get every block
231 part
+=self
.section_parser(section
)
232 info_dict
[str_id
] = self
.section_parser(section
)
239 section
= read
.split('\nQ')
240 part
+=self
.section_parser(section
)
241 info_dict
[str_id
] = self
.section_parser(section
)
245 def eval_id(self
,id):
247 default_id
=id[0:len(id)//2]
248 platform_id
=id[len(id)//2:]
250 for i
in range(len(default_id
)):
251 text
+="%s.common.%s.%s,"%(SECTION
,self
.id_name(platform_id
[i
],'PLATFORM'),self
.id_name(default_id
[i
],'DEFAULT'))
252 return '\n[%s]\n'%text
[:-1]
254 def id_name(self
,ID
, flag
):
255 platform_dict
= {'0': 'DEFAULT'}
256 default_dict
= {'0': 'STANDARD', '1': 'MANUFACTURING'}
257 if flag
== "PLATFORM":
259 value
= platform_dict
[ID
]
261 value
= 'SKUID%s' % ID
262 elif flag
== 'DEFAULT':
264 value
= default_dict
[ID
]
266 value
= 'DEFAULTID%s' % ID
271 def section_parser(self
,section
):
272 offset_re
= re
.compile(r
'offset=(\w+)')
273 name_re
= re
.compile(r
'name=(\S+)')
274 guid_re
= re
.compile(r
'guid=(\S+)')
275 # help_re = re.compile(r'help = (.*)')
276 attribute_re
=re
.compile(r
'attribute=(\w+)')
277 value_re
= re
.compile(r
'(//.*)')
279 for x
in section
[1:]:
280 line
=x
.split('\n')[0]
281 line
=value_re
.sub('',line
) #delete \\... in "Q...." line
282 list1
=line
.split(' ')
283 value
=self
.value_parser(list1
)
284 offset
= offset_re
.findall(x
.replace(' ',''))
285 name
= name_re
.findall(x
.replace(' ',''))
286 guid
= guid_re
.findall(x
.replace(' ',''))
287 attribute
=attribute_re
.findall(x
.replace(' ',''))
288 if offset
and name
and guid
and value
and attribute
:
289 if attribute
[0] in ['0x3','0x7']:
290 offset
= int(offset
[0], 16)
291 #help = help_re.findall(x)
292 text
= offset
, name
[0], guid
[0], value
, attribute
[0]
296 def value_parser(self
, list1
):
297 list1
= [t
for t
in list1
if t
!= ''] # remove '' form list
298 first_num
= int(list1
[0], 16)
299 if list1
[first_num
+ 1] == 'STRING': # parser STRING
300 if list1
[-1] == '""':
303 value
= 'L%s' % list1
[-1]
304 elif list1
[first_num
+ 1] == 'ORDERED_LIST': # parser ORDERED_LIST
305 value_total
= int(list1
[first_num
+ 2])
306 list2
= list1
[-value_total
:]
310 if len(i
) % 2 == 0 and len(i
) != 2:
311 for m
in range(0, len(i
) // 2):
312 tmp
.append('0x%02x' % (int('0x%s' % i
, 16) >> m
* 8 & 0xff))
314 tmp
.append('0x%s' % i
)
317 value
= '{%s}' % line
[:-1]
319 value
= "0x%01x" % int(list1
[-1], 16)
323 #parser Guid file, get guid name form guid value
326 def __init__(self
,path
):
328 self
.guidfile
= self
.gfile()
329 self
.guiddict
= self
.guid_dict()
332 for root
, dir, file in os
.walk(self
.path
, topdown
=True, followlinks
=False):
334 gfile
= os
.path
.join(root
,'Fv','Guid.xref')
335 if os
.path
.isfile(gfile
):
338 print("ERROR: Guid.xref file not found")
339 ERRORMSG
.append("ERROR: Guid.xref file not found")
344 with
open(self
.guidfile
,'r') as file:
345 lines
= file.readlines()
347 for line
in guidinfo
:
348 list=line
.strip().split(' ')
351 guiddict
[list[0].upper()]=list[1]
352 elif list[0] != ''and len(list)==1:
353 print("Error: line %s can't be parser in %s"%(line
.strip(),self
.guidfile
))
354 ERRORMSG
.append("Error: line %s can't be parser in %s"%(line
.strip(),self
.guidfile
))
356 print("ERROR: No data in %s" %self
.guidfile
)
357 ERRORMSG
.append("ERROR: No data in %s" %self
.guidfile
)
360 def guid_parser(self
,guid
):
361 if guid
.upper() in self
.guiddict
:
362 return self
.guiddict
[guid
.upper()]
364 print("ERROR: GUID %s not found in file %s"%(guid
, self
.guidfile
))
365 ERRORMSG
.append("ERROR: GUID %s not found in file %s"%(guid
, self
.guidfile
))
370 def __init__(self
,path
):
372 self
.rootdir
=self
.get_root_dir()
375 for path
in self
.rootdir
:
376 for o_root
, o_dir
, o_file
in os
.walk(os
.path
.join(path
, "OUTPUT"), topdown
=True, followlinks
=False):
378 if os
.path
.splitext(INF
)[1] == '.inf':
379 for l_root
, l_dir
, l_file
in os
.walk(os
.path
.join(path
, "DEBUG"), topdown
=True,
382 if os
.path
.splitext(LST
)[1] == '.lst':
383 self
.lstinf
[os
.path
.join(l_root
, LST
)] = os
.path
.join(o_root
, INF
)
384 self
.usefuldir
.add(path
)
386 def get_root_dir(self
):
388 for root
,dir,file in os
.walk(self
.path
,topdown
=True,followlinks
=False):
390 updir
=root
.split("OUTPUT",1)[0]
391 rootdir
.append(updir
)
392 rootdir
=list(set(rootdir
))
400 package_re
=re
.compile(r
'Packages\.\w+]\n(.*)',re
.S
)
401 for i
in list(self
.lstinf
.values()):
402 with
open(i
,'r') as inf
:
404 section
=read
.split('[')
406 p
=package_re
.findall(j
)
408 package
[i
]=p
[0].rstrip()
411 def header(self
,struct
):
413 head_re
= re
.compile('typedef.*} %s;[\n]+(.*)(?:typedef|formset)'%struct
,re
.M|re
.S
)
414 head_re2
= re
.compile(r
'#line[\s\d]+"(\S+h)"')
415 for i
in list(self
.lstinf
.keys()):
416 with
open(i
,'r') as lst
:
418 h
= head_re
.findall(read
)
420 head
=head_re2
.findall(h
[0])
422 format
= head
[0].replace('\\\\','/').replace('\\','/')
423 name
=format
.split('/')[-1]
424 head
= self
.headerfileset
.get(name
)
426 head
= head
.replace('\\','/')
427 header
[struct
] = head
430 def headerfileset(self
):
432 for root
,dirs
,files
in os
.walk(self
.path
):
434 if os
.path
.basename(file) == 'deps.txt':
435 with
open(os
.path
.join(root
,file),"r") as fr
:
436 for line
in fr
.readlines():
437 headerset
[os
.path
.basename(line
).strip()] = line
.strip()
440 def makefile(self
,filename
):
441 re_format
= re
.compile(r
'DEBUG_DIR.*(?:\S+Pkg)\\(.*\\%s)'%filename
)
442 for i
in self
.usefuldir
:
443 with
open(os
.path
.join(i
,'Makefile'),'r') as make
:
445 dir = re_format
.findall(read
)
450 class mainprocess(object):
452 def __init__(self
,InputPath
,Config
,OutputPath
):
453 self
.init
= 0xFCD00000
454 self
.inputpath
= os
.path
.abspath(InputPath
)
455 self
.outputpath
= os
.path
.abspath(OutputPath
)
456 self
.LST
= PATH(self
.inputpath
)
457 self
.lst_dict
= self
.LST
.lst_inf()
459 self
.attribute_dict
= {'0x3': 'NV, BS', '0x7': 'NV, BS, RT'}
460 self
.guid
= GUID(self
.inputpath
)
464 conf
=Config(self
.Config
)
465 config_dict
=conf
.config_parser() #get {'0_0':[offset,name,guid,value,attribute]...,'1_0':....}
466 lst
=parser_lst(list(self
.lst_dict
.keys()))
467 efi_dict
=lst
.efivarstore_parser() #get {name:struct} form lst file
468 keys
=sorted(config_dict
.keys())
469 all_struct
=lst
.struct()
470 stru_lst
=lst
.struct_lst()
476 tmp
= self
.LST
.header(i
)
477 self
.header
.update(tmp
)
479 tmp_id
=[id_key
] #['0_0',[(struct,[name...]),(struct,[name...])]]
480 tmp_info
={} #{name:struct}
481 for section
in config_dict
[id_key
]:
482 c_offset
,c_name
,c_guid
,c_value
,c_attribute
= section
483 if c_name
in efi_dict
:
484 struct
= efi_dict
[c_name
]
485 title
='%s%s|L"%s"|%s|0x00||%s\n'%(PCD_NAME
,c_name
,c_name
,self
.guid
.guid_parser(c_guid
),self
.attribute_dict
[c_attribute
])
486 if struct
in all_struct
:
487 lstfile
= stru_lst
[struct
]
488 struct_dict
=all_struct
[struct
]
490 title2
= '%s%s|{0}|%s|0xFCD00000{\n <HeaderFiles>\n %s\n <Packages>\n%s\n}\n' % (PCD_NAME
, c_name
, struct
, self
.header
[struct
], self
.LST
.package()[self
.lst_dict
[lstfile
]])
492 WARNING
.append("Warning: No <HeaderFiles> for struct %s"%struct
)
493 title2
= '%s%s|{0}|%s|0xFCD00000{\n <HeaderFiles>\n %s\n <Packages>\n%s\n}\n' % (PCD_NAME
, c_name
, struct
, '', self
.LST
.package()[self
.lst_dict
[lstfile
]])
494 header_list
.append(title2
)
495 elif struct
not in lst
._ignore
:
497 print("ERROR: Struct %s can't found in lst file" %struct
)
498 ERRORMSG
.append("ERROR: Struct %s can't found in lst file" %struct
)
499 if c_offset
in struct_dict
:
500 offset_name
=struct_dict
[c_offset
]
501 info
= "%s%s.%s|%s\n"%(PCD_NAME
,c_name
,offset_name
,c_value
)
502 inf
= "%s%s\n"%(PCD_NAME
,c_name
)
506 print("ERROR: Can't find offset %s with struct name %s"%(c_offset
,struct
))
507 ERRORMSG
.append("ERROR: Can't find offset %s with name %s"%(c_offset
,struct
))
509 print("ERROR: Can't find name %s in lst file"%(c_name))
510 ERRORMSG
.append("ERROR: Can't find name %s in lst file"%(c_name))
511 tmp_id
.append(list(self
.reverse_dict(tmp_info
).items()))
512 id,tmp_title_list
,tmp_info_list
= self
.read_list(tmp_id
)
513 title_list
+=tmp_title_list
514 info_list
.append(tmp_info_list
)
515 inf_list
= self
.del_repeat(inf_list
)
516 header_list
= self
.plus(self
.del_repeat(header_list
))
517 title_all
=list(set(title_list
))
518 info_list
= self
.remove_bracket(self
.del_repeat(info_list
))
519 for i
in range(len(info_list
)-1,-1,-1):
520 if len(info_list
[i
]) == 0:
521 info_list
.remove(info_list
[i
])
522 for i
in (inf_list
, title_all
, header_list
):
524 return keys
,title_all
,info_list
,header_list
,inf_list
526 def remove_bracket(self
,List
):
530 if (('L"' in j
) and ("[" in j
)) or (tmp
[1].strip() == '{0x0, 0x0}'):
531 tmp
[0] = tmp
[0][:tmp
[0].index('[')]
532 List
[List
.index(i
)][i
.index(j
)] = "|".join(tmp
)
534 List
[List
.index(i
)][i
.index(j
)] = j
536 if type(i
) == type([0,0]):
543 if not os
.path
.isdir(self
.outputpath
):
544 os
.makedirs(self
.outputpath
)
545 decwrite
= write2file(os
.path
.join(self
.outputpath
,'StructurePcd.dec'))
546 dscwrite
= write2file(os
.path
.join(self
.outputpath
,'StructurePcd.dsc'))
547 infwrite
= write2file(os
.path
.join(self
.outputpath
, 'StructurePcd.inf'))
548 conf
= Config(self
.Config
)
549 ids
,title
,info
,header
,inf
=self
.main()
550 decwrite
.add2file(decstatement
)
551 decwrite
.add2file(header
)
552 infwrite
.add2file(infstatement
)
553 infwrite
.add2file(inf
)
554 dscwrite
.add2file(dscstatement
)
556 dscwrite
.add2file(conf
.eval_id(id))
558 dscwrite
.add2file(title
)
561 dscwrite
.add2file(info
)
564 dscwrite
.add2file(info
[0])
567 dscwrite
.add2file(info
[1])
569 def del_repeat(self
,List
):
570 if len(List
) == 1 or len(List
) == 0:
573 if type(List
[0]) != type('xxx'):
575 for i
in range(len(List
)):
577 alist
.append(List
[0])
582 alist
.append(self
.__del
(list(set(plist
)), List
[i
]))
585 return list(set(List
))
588 def __del(self
,list1
,list2
):
589 return list(set(list2
).difference(set(list1
)))
591 def reverse_dict(self
,dict):
593 for i
in list(dict.items()):
594 if i
[1] not in list(data
.keys()):
597 data
[i
[1]].append(i
[0])
600 def read_list(self
,list):
604 title_list
.append(i
[0])
607 return list[0],title_list
,info_list
612 if type(i
) != type([0]):
614 num
= "0x%01x" % self
.init
615 j
=i
.replace('0xFCD00000',num
.upper())
619 class write2file(object):
621 def __init__(self
,Output
):
624 if os
.path
.exists(self
.output
):
625 os
.remove(self
.output
)
627 def add2file(self
,content
):
629 with
open(self
.output
,'a+') as file:
630 file.write(self
.__gen
(content
))
632 def __gen(self
,content
):
633 if type(content
) == type(''):
635 elif type(content
) == type([0,0])or type(content
) == type((0,0)):
636 return self
.__readlist
(content
)
637 elif type(content
) == type({0:0}):
638 return self
.__readdict
(content
)
640 def __readlist(self
,list):
642 if type(i
) == type([0,0])or type(i
) == type((0,0)):
644 elif type(i
) == type('') :
648 def __readdict(self
,dict):
649 content
=list(dict.items())
650 return self
.__readlist
(content
)
653 return datetime
.datetime
.now()
655 def dtime(start
,end
,id=None):
658 print("%s time:%s" % (id,str(end
- start
)))
660 print("Total time:%s" %str
(end
-start
)[:-7])
665 parser
= argparse
.ArgumentParser(prog
= __prog__
,
666 description
= __description__
+ __copyright__
,
667 conflict_handler
= 'resolve')
668 parser
.add_argument('-v', '--version', action
= 'version',version
= __version__
, help="show program's version number and exit")
669 parser
.add_argument('-p', '--path', metavar
='PATH', dest
='path', help="platform build output directory")
670 parser
.add_argument('-c', '--config',metavar
='FILENAME', dest
='config', help="firmware configuration file")
671 parser
.add_argument('-o', '--outputdir', metavar
='PATH', dest
='output', help="output directoy")
672 options
= parser
.parse_args()
676 run
= mainprocess(options
.path
, options
.config
, options
.output
)
680 warning
= list(set(WARNING
))
684 ERROR
= list(set(ERRORMSG
))
685 with
open("ERROR.log", 'w+') as error
:
687 error
.write(i
+ '\n')
688 print("Some error find, error log in ERROR.log")
689 print('Finished, Output files in directory %s'%os.path
.abspath(options
.output
))
691 print('Error command, no output path, use -h for help')
693 print('Error command, no build path input, use -h for help')
695 print('Error command, no output file, use -h for help')
699 if __name__
== '__main__':