]>
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 # This program and the accompanying materials
10 # are licensed and made available under the terms and conditions of the BSD License
11 # which accompanies this distribution. The full text of the license may be found at
12 # http://opensource.org/licenses/bsd-license.php
14 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 ConvertFceToStructurePcd
28 # Globals for help information
30 __prog__
= 'ConvertFceToStructurePcd'
31 __version__
= '%s Version %s' % (__prog__
, '0.1 ')
32 __copyright__
= 'Copyright (c) 2018, Intel Corporation. All rights reserved.'
33 __description__
= 'Generate Structure PCD in DEC/DSC/INF based on Firmware Configuration.\n'
36 dscstatement
='''[Defines]
37 VPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E08
40 0|DEFAULT # The entry: 0|DEFAULT is reserved and always required.
43 0|STANDARD # UEFI Standard default 0|STANDARD is reserved.
44 1|MANUFACTURING # UEFI Manufacturing default 1|MANUFACTURING is reserved.
46 [PcdsDynamicExVpd.common.DEFAULT]
47 gEfiMdeModulePkgTokenSpaceGuid.PcdNvStoreDefaultValueBuffer|*
50 decstatement
= '''[Guids]
51 gStructPcdTokenSpaceGuid = {0x3f1406f4, 0x2b, 0x487a, {0x8b, 0x69, 0x74, 0x29, 0x1b, 0x36, 0x16, 0xf4}}
53 [PcdsFixedAtBuild,PcdsPatchableInModule,PcdsDynamic,PcdsDynamicEx]
56 infstatement
= '''[Pcd]
59 SECTION
='PcdsDynamicHii'
60 PCD_NAME
='gStructPcdTokenSpaceGuid.Pcd'
65 class parser_lst(object):
67 def __init__(self
,filelist
):
68 self
._ignore
=['BOOLEAN', 'UINT8', 'UINT16', 'UINT32', 'UINT64']
70 self
.text
=self
.megre_lst()[0]
71 self
.content
=self
.megre_lst()[1]
76 for file in self
.file:
77 with
open(file,'r') as f
:
81 return alltext
,content
83 def struct_lst(self
):#{struct:lst file}
85 name_format
= re
.compile(r
'(?<!typedef)\s+struct (\w+) {.*?;', re
.S
)
86 for i
in list(self
.content
.keys()):
87 structs
= name_format
.findall(self
.content
[i
])
90 if j
not in self
._ignore
:
96 def struct(self
):#struct:{offset:name}
97 unit_num
= re
.compile('(\d+)')
98 offset1_re
= re
.compile('(\d+)\[')
99 pcdname_num_re
= re
.compile('\w+\[(\S+)\]')
100 pcdname_re
= re
.compile('\](.*)\<')
101 pcdname2_re
= re
.compile('(\w+)\[')
102 uint_re
= re
.compile('\<(\S+)\>')
103 name_format
= re
.compile(r
'(?<!typedef)\s+struct (\w+) {.*?;', re
.S
)
104 name
=name_format
.findall(self
.text
)
108 tmp_n
= [n
for n
in name
if n
not in self
._ignore
]
109 name
= list(set(tmp_n
))
110 name
.sort(key
= tmp_n
.index
)
112 #name=list(set(name).difference(set(self._ignore)))
114 s_re
= re
.compile(r
'struct %s :(.*?)};'% struct
, re
.S
)
115 content
= s_re
.search(self
.text
)
118 text
= content
.group().split('+')
119 for line
in text
[1:]:
120 offset
= offset1_re
.findall(line
)
121 t_name
= pcdname_re
.findall(line
)
122 uint
= uint_re
.findall(line
)
127 t_name
= t_name
[0].strip()
128 if (' ' in t_name
) or ("=" in t_name
) or (";" in t_name
) or("\\" in name
) or (t_name
==''):
129 WARNING
.append("Warning:Invalid Pcd name '%s' for Offset %s in struct %s" % (t_name
,offset
, struct
))
132 if uint
in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
133 offset
= int(offset
, 10)
134 tmp_name
= pcdname2_re
.findall(t_name
)[0] + '[0]'
135 tmp_dict
[offset
] = tmp_name
136 pcdname_num
= int(pcdname_num_re
.findall(t_name
)[0],10)
137 uint
= int(unit_num
.findall(uint
)[0],10)
139 for i
in range(1, pcdname_num
):
141 tmp_name
= pcdname2_re
.findall(t_name
)[0] + '[%s]' % i
142 tmp_dict
[offset
] = tmp_name
144 tmp_name
= pcdname2_re
.findall(t_name
)[0]
145 pcdname_num
= pcdname_num_re
.findall(t_name
)[0]
146 line
= [offset
,tmp_name
,pcdname_num
,uint
]
150 if uint
not in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
151 line
= [offset
, t_name
, 0, uint
]
155 offset
= int(offset
,10)
156 tmp_dict
[offset
] = t_name
157 info
[struct
] = tmp_dict
158 if len(unparse
) != 0:
160 if u
[3] in list(info
.keys()):
161 unpar
= self
.nameISstruct(u
,info
[u
[3]])
162 info
[u
[4]]= dict(list(info
[u
[4]].items())+list(unpar
[u
[4]].items()))
164 print("ERROR: No struct name found in %s" % self
.file)
165 ERRORMSG
.append("ERROR: No struct name found in %s" % self
.file)
169 def nameISstruct(self
,line
,key_dict
):
172 s_re
= re
.compile(r
'struct %s :(.*?)};' % line
[3], re
.S
)
173 size_re
= re
.compile(r
'mTotalSize \[(\S+)\]')
174 content
= s_re
.search(self
.text
)
176 s_size
= size_re
.findall(content
.group())[0]
179 print("ERROR: Struct %s not define mTotalSize in lst file" %line
[3])
180 ERRORMSG
.append("ERROR: Struct %s not define mTotalSize in lst file" %line
[3])
181 size
= int(line
[0], 10)
183 for j
in range(0, int(line
[2], 10)):
184 for k
in list(key_dict
.keys()):
186 name
='%s.%s' %((line
[1]+'[%s]'%j
),key_dict
[k
])
188 size
= int(s_size
,16)+size
190 for k
in list(key_dict
.keys()):
192 name
= '%s.%s' % (line
[1], key_dict
[k
])
194 dict2
[line
[4]] = dict
197 def efivarstore_parser(self
):
198 efivarstore_format
= re
.compile(r
'efivarstore.*?;', re
.S
)
199 struct_re
= re
.compile(r
'efivarstore(.*?),',re
.S
)
200 name_re
= re
.compile(r
'name=(\w+)')
202 efitxt
= efivarstore_format
.findall(self
.text
)
204 struct
= struct_re
.findall(i
.replace(' ',''))
205 name
= name_re
.findall(i
.replace(' ',''))
207 efivarstore_dict
[name
[0]]=struct
[0]
209 print("ERROR: Can't find Struct or name in lst file, please check have this format:efivarstore XXXX, name=xxxx")
210 ERRORMSG
.append("ERROR: Can't find Struct or name in lst file, please check have this format:efivarstore XXXX, name=xxxx")
211 return efivarstore_dict
213 class Config(object):
215 def __init__(self
,Config
):
218 #Parser .config file,return list[offset,name,guid,value,help]
219 def config_parser(self
):
220 ids_re
=re
.compile('_ID:(\d+)',re
.S
)
221 id_re
= re
.compile('\s+')
224 with
open(self
.config
, 'r') as text
:
226 if 'DEFAULT_ID:' in read
:
227 all_txt
= read
.split('FCEKEY DEFAULT')
228 for i
in all_txt
[1:]:
229 part
= [] #save all infomation for DEFAULT_ID
231 ids
= ids_re
.findall(i
.replace(' ',''))
236 section
= i
.split('\nQ') #split with '\nQ ' to get every block
237 part
+=self
.section_parser(section
)
238 info_dict
[str_id
] = self
.section_parser(section
)
245 section
= read
.split('\nQ')
246 part
+=self
.section_parser(section
)
247 info_dict
[str_id
] = self
.section_parser(section
)
251 def eval_id(self
,id):
253 default_id
=id[0:len(id)//2]
254 platform_id
=id[len(id)//2:]
256 for i
in range(len(default_id
)):
257 text
+="%s.common.%s.%s,"%(SECTION
,self
.id_name(platform_id
[i
],'PLATFORM'),self
.id_name(default_id
[i
],'DEFAULT'))
258 return '\n[%s]\n'%text
[:-1]
260 def id_name(self
,ID
, flag
):
261 platform_dict
= {'0': 'DEFAULT'}
262 default_dict
= {'0': 'STANDARD', '1': 'MANUFACTURING'}
263 if flag
== "PLATFORM":
265 value
= platform_dict
[ID
]
267 value
= 'SKUID%s' % ID
268 elif flag
== 'DEFAULT':
270 value
= default_dict
[ID
]
272 value
= 'DEFAULTID%s' % ID
277 def section_parser(self
,section
):
278 offset_re
= re
.compile(r
'offset=(\w+)')
279 name_re
= re
.compile(r
'name=(\S+)')
280 guid_re
= re
.compile(r
'guid=(\S+)')
281 # help_re = re.compile(r'help = (.*)')
282 attribute_re
=re
.compile(r
'attribute=(\w+)')
283 value_re
= re
.compile(r
'(//.*)')
285 for x
in section
[1:]:
286 line
=x
.split('\n')[0]
287 line
=value_re
.sub('',line
) #delete \\... in "Q...." line
288 list1
=line
.split(' ')
289 value
=self
.value_parser(list1
)
290 offset
= offset_re
.findall(x
.replace(' ',''))
291 name
= name_re
.findall(x
.replace(' ',''))
292 guid
= guid_re
.findall(x
.replace(' ',''))
293 attribute
=attribute_re
.findall(x
.replace(' ',''))
294 if offset
and name
and guid
and value
and attribute
:
295 if attribute
[0] in ['0x3','0x7']:
296 offset
= int(offset
[0], 16)
297 #help = help_re.findall(x)
298 text
= offset
, name
[0], guid
[0], value
, attribute
[0]
302 def value_parser(self
, list1
):
303 list1
= [t
for t
in list1
if t
!= ''] # remove '' form list
304 first_num
= int(list1
[0], 16)
305 if list1
[first_num
+ 1] == 'STRING': # parser STRING
306 if list1
[-1] == '""':
309 value
= 'L%s' % list1
[-1]
310 elif list1
[first_num
+ 1] == 'ORDERED_LIST': # parser ORDERED_LIST
311 value_total
= int(list1
[first_num
+ 2])
312 list2
= list1
[-value_total
:]
316 if len(i
) % 2 == 0 and len(i
) != 2:
317 for m
in range(0, len(i
) // 2):
318 tmp
.append('0x%02x' % (int('0x%s' % i
, 16) >> m
* 8 & 0xff))
320 tmp
.append('0x%s' % i
)
323 value
= '{%s}' % line
[:-1]
325 value
= "0x%01x" % int(list1
[-1], 16)
329 #parser Guid file, get guid name form guid value
332 def __init__(self
,path
):
334 self
.guidfile
= self
.gfile()
335 self
.guiddict
= self
.guid_dict()
338 for root
, dir, file in os
.walk(self
.path
, topdown
=True, followlinks
=False):
340 gfile
= os
.path
.join(root
,'Fv','Guid.xref')
341 if os
.path
.isfile(gfile
):
344 print("ERROR: Guid.xref file not found")
345 ERRORMSG
.append("ERROR: Guid.xref file not found")
350 with
open(self
.guidfile
,'r') as file:
351 lines
= file.readlines()
353 for line
in guidinfo
:
354 list=line
.strip().split(' ')
357 guiddict
[list[0].upper()]=list[1]
358 elif list[0] != ''and len(list)==1:
359 print("Error: line %s can't be parser in %s"%(line
.strip(),self
.guidfile
))
360 ERRORMSG
.append("Error: line %s can't be parser in %s"%(line
.strip(),self
.guidfile
))
362 print("ERROR: No data in %s" %self
.guidfile
)
363 ERRORMSG
.append("ERROR: No data in %s" %self
.guidfile
)
366 def guid_parser(self
,guid
):
367 if guid
.upper() in self
.guiddict
:
368 return self
.guiddict
[guid
.upper()]
370 print("ERROR: GUID %s not found in file %s"%(guid
, self
.guidfile
))
371 ERRORMSG
.append("ERROR: GUID %s not found in file %s"%(guid
, self
.guidfile
))
376 def __init__(self
,path
):
378 self
.rootdir
=self
.get_root_dir()
381 for path
in self
.rootdir
:
382 for o_root
, o_dir
, o_file
in os
.walk(os
.path
.join(path
, "OUTPUT"), topdown
=True, followlinks
=False):
384 if os
.path
.splitext(INF
)[1] == '.inf':
385 for l_root
, l_dir
, l_file
in os
.walk(os
.path
.join(path
, "DEBUG"), topdown
=True,
388 if os
.path
.splitext(LST
)[1] == '.lst':
389 self
.lstinf
[os
.path
.join(l_root
, LST
)] = os
.path
.join(o_root
, INF
)
390 self
.usefuldir
.append(path
)
392 def get_root_dir(self
):
394 for root
,dir,file in os
.walk(self
.path
,topdown
=True,followlinks
=False):
396 updir
=root
.split("OUTPUT",1)[0]
397 rootdir
.append(updir
)
398 rootdir
=list(set(rootdir
))
406 package_re
=re
.compile(r
'Packages\.\w+]\n(.*)',re
.S
)
407 for i
in list(self
.lstinf
.values()):
408 with
open(i
,'r') as inf
:
410 section
=read
.split('[')
412 p
=package_re
.findall(j
)
414 package
[i
]=p
[0].rstrip()
417 def header(self
,struct
):
419 head_re
= re
.compile('typedef.*} %s;[\n]+(.*?)(?:typedef|formset)'%struct
,re
.M|re
.S
)
420 head_re2
= re
.compile(r
'#line[\s\d]+"(\S+h)"')
421 for i
in list(self
.lstinf
.keys()):
422 with
open(i
,'r') as lst
:
424 h
= head_re
.findall(read
)
426 head
=head_re2
.findall(h
[0])
428 format
= head
[0].replace('\\\\','/').replace('\\','/')
429 name
=format
.split('/')[-1]
430 head
= self
.makefile(name
).replace('\\','/')
431 header
[struct
] = head
434 def makefile(self
,filename
):
435 re_format
= re
.compile(r
'DEBUG_DIR.*(?:\S+Pkg)\\(.*\\%s)'%filename
)
436 for i
in self
.usefuldir
:
437 with
open(os
.path
.join(i
,'Makefile'),'r') as make
:
439 dir = re_format
.findall(read
)
443 class mainprocess(object):
445 def __init__(self
,InputPath
,Config
,OutputPath
):
446 self
.init
= 0xFCD00000
447 self
.inputpath
= os
.path
.abspath(InputPath
)
448 self
.outputpath
= os
.path
.abspath(OutputPath
)
449 self
.LST
= PATH(self
.inputpath
)
450 self
.lst_dict
= self
.LST
.lst_inf()
452 self
.attribute_dict
= {'0x3': 'NV, BS', '0x7': 'NV, BS, RT'}
453 self
.guid
= GUID(self
.inputpath
)
457 conf
=Config(self
.Config
)
458 config_dict
=conf
.config_parser() #get {'0_0':[offset,name,guid,value,attribute]...,'1_0':....}
459 lst
=parser_lst(list(self
.lst_dict
.keys()))
460 efi_dict
=lst
.efivarstore_parser() #get {name:struct} form lst file
461 keys
=sorted(config_dict
.keys())
462 all_struct
=lst
.struct()
463 stru_lst
=lst
.struct_lst()
469 tmp
= self
.LST
.header(i
)
470 self
.header
.update(tmp
)
472 tmp_id
=[id_key
] #['0_0',[(struct,[name...]),(struct,[name...])]]
473 tmp_info
={} #{name:struct}
474 for section
in config_dict
[id_key
]:
475 c_offset
,c_name
,c_guid
,c_value
,c_attribute
= section
476 if c_name
in efi_dict
:
477 struct
= efi_dict
[c_name
]
478 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
])
479 if struct
in all_struct
:
480 lstfile
= stru_lst
[struct
]
481 struct_dict
=all_struct
[struct
]
483 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
]])
485 WARNING
.append("Warning: No <HeaderFiles> for struct %s"%struct
)
486 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
]])
487 header_list
.append(title2
)
490 print("ERROR: Struct %s can't found in lst file" %struct
)
491 ERRORMSG
.append("ERROR: Struct %s can't found in lst file" %struct
)
492 if c_offset
in struct_dict
:
493 offset_name
=struct_dict
[c_offset
]
494 info
= "%s%s.%s|%s\n"%(PCD_NAME
,c_name
,offset_name
,c_value
)
495 inf
= "%s%s\n"%(PCD_NAME
,c_name
)
499 print("ERROR: Can't find offset %s with struct name %s"%(c_offset
,struct
))
500 ERRORMSG
.append("ERROR: Can't find offset %s with name %s"%(c_offset
,struct
))
502 print("ERROR: Can't find name %s in lst file"%(c_name))
503 ERRORMSG
.append("ERROR: Can't find name %s in lst file"%(c_name))
504 tmp_id
.append(list(self
.reverse_dict(tmp_info
).items()))
505 id,tmp_title_list
,tmp_info_list
= self
.read_list(tmp_id
)
506 title_list
+=tmp_title_list
507 info_list
.append(tmp_info_list
)
508 inf_list
= self
.del_repeat(inf_list
)
509 header_list
= self
.plus(self
.del_repeat(header_list
))
510 title_all
=list(set(title_list
))
511 info_list
= self
.remove_bracket(self
.del_repeat(info_list
))
512 for i
in range(len(info_list
)-1,-1,-1):
513 if len(info_list
[i
]) == 0:
514 info_list
.remove(info_list
[i
])
515 return keys
,title_all
,info_list
,header_list
,inf_list
517 def remove_bracket(self
,List
):
521 if (('L"' in j
) and ("[" in j
)) or (tmp
[1].strip() == '{0x0, 0x0}'):
522 tmp
[0] = tmp
[0][:tmp
[0].index('[')]
523 List
[List
.index(i
)][i
.index(j
)] = "|".join(tmp
)
525 List
[List
.index(i
)][i
.index(j
)] = j
531 if not os
.path
.isdir(self
.outputpath
):
532 os
.makedirs(self
.outputpath
)
533 decwrite
= write2file(os
.path
.join(self
.outputpath
,'StructurePcd.dec'))
534 dscwrite
= write2file(os
.path
.join(self
.outputpath
,'StructurePcd.dsc'))
535 infwrite
= write2file(os
.path
.join(self
.outputpath
, 'StructurePcd.inf'))
536 conf
= Config(self
.Config
)
537 ids
,title
,info
,header
,inf
=self
.main()
538 decwrite
.add2file(decstatement
)
539 decwrite
.add2file(header
)
540 infwrite
.add2file(infstatement
)
541 infwrite
.add2file(inf
)
542 dscwrite
.add2file(dscstatement
)
544 dscwrite
.add2file(conf
.eval_id(id))
546 dscwrite
.add2file(title
)
549 dscwrite
.add2file(info
)
552 dscwrite
.add2file(info
[0])
555 dscwrite
.add2file(info
[1])
557 def del_repeat(self
,List
):
558 if len(List
) == 1 or len(List
) == 0:
561 if type(List
[0]) != type('xxx'):
563 for i
in range(len(List
)):
565 alist
.append(List
[0])
570 alist
.append(self
.__del
(list(set(plist
)), List
[i
]))
573 return list(set(List
))
576 def __del(self
,list1
,list2
):
577 return list(set(list2
).difference(set(list1
)))
579 def reverse_dict(self
,dict):
581 for i
in list(dict.items()):
582 if i
[1] not in list(data
.keys()):
585 data
[i
[1]].append(i
[0])
588 def read_list(self
,list):
592 title_list
.append(i
[0])
595 return list[0],title_list
,info_list
600 if type(i
) != type([0]):
602 num
= "0x%01x" % self
.init
603 j
=i
.replace('0xFCD00000',num
.upper())
607 class write2file(object):
609 def __init__(self
,Output
):
612 if os
.path
.exists(self
.output
):
613 os
.remove(self
.output
)
615 def add2file(self
,content
):
617 with
open(self
.output
,'a+') as file:
618 file.write(self
.__gen
(content
))
620 def __gen(self
,content
):
621 if type(content
) == type(''):
623 elif type(content
) == type([0,0])or type(content
) == type((0,0)):
624 return self
.__readlist
(content
)
625 elif type(content
) == type({0:0}):
626 return self
.__readdict
(content
)
628 def __readlist(self
,list):
630 if type(i
) == type([0,0])or type(i
) == type((0,0)):
632 elif type(i
) == type('') :
636 def __readdict(self
,dict):
637 content
=list(dict.items())
638 return self
.__readlist
(content
)
641 return datetime
.datetime
.now()
643 def dtime(start
,end
,id=None):
646 print("%s time:%s" % (id,str(end
- start
)))
648 print("Total time:%s" %str
(end
-start
)[:-7])
653 parser
= argparse
.ArgumentParser(prog
= __prog__
,
654 description
= __description__
+ __copyright__
,
655 conflict_handler
= 'resolve')
656 parser
.add_argument('-v', '--version', action
= 'version',version
= __version__
, help="show program's version number and exit")
657 parser
.add_argument('-p', '--path', metavar
='PATH', dest
='path', help="platform build output directory")
658 parser
.add_argument('-c', '--config',metavar
='FILENAME', dest
='config', help="firmware configuration file")
659 parser
.add_argument('-o', '--outputdir', metavar
='PATH', dest
='output', help="output directoy")
660 options
= parser
.parse_args()
664 run
= mainprocess(options
.path
, options
.config
, options
.output
)
668 warning
= list(set(WARNING
))
672 ERROR
= list(set(ERRORMSG
))
673 with
open("ERROR.log", 'w+') as error
:
675 error
.write(i
+ '\n')
676 print("Some error find, error log in ERROR.log")
677 print('Finished, Output files in directory %s'%os.path
.abspath(options
.output
))
679 print('Error command, no output path, use -h for help')
681 print('Error command, no build path input, use -h for help')
683 print('Error command, no output file, use -h for help')
687 if __name__
== '__main__':