06e426aa16bb8c86b5bf1a6aae3f267f52b28444
[mirror_edk2.git] / IntelFspPkg / Tools / GenCfgOpt.py
1 ## @ GenCfgOpt.py
2 #
3 # Copyright (c) 2014 - 2015, Intel Corporation. All rights reserved.<BR>
4 # This program and the accompanying materials are licensed and made available under
5 # the terms and conditions of the BSD License that accompanies this distribution.
6 # The full text of the license may be found at
7 # http://opensource.org/licenses/bsd-license.php.
8 #
9 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 #
12 ##
13
14 import os
15 import re
16 import sys
17 import struct
18 from datetime import date
19
20 # Generated file copyright header
21
22 __copyright_txt__ = """## @file
23 #
24 # THIS IS AUTO-GENERATED FILE BY BUILD TOOLS AND PLEASE DO NOT MAKE MODIFICATION.
25 #
26 # This file lists all VPD informations for a platform collected by build.exe.
27 #
28 # Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
29 # This program and the accompanying materials
30 # are licensed and made available under the terms and conditions of the BSD License
31 # which accompanies this distribution. The full text of the license may be found at
32 # http://opensource.org/licenses/bsd-license.php
33 #
34 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
35 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
36 #
37 """
38
39 __copyright_bsf__ = """/** @file
40
41 Boot Setting File for Platform Configuration.
42
43 Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
44 This program and the accompanying materials
45 are licensed and made available under the terms and conditions of the BSD License
46 which accompanies this distribution. The full text of the license may be found at
47 http://opensource.org/licenses/bsd-license.php
48
49 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
50 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
51
52 This file is automatically generated. Please do NOT modify !!!
53
54 **/
55
56 """
57
58 __copyright_h__ = """/** @file
59
60 Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>
61
62 Redistribution and use in source and binary forms, with or without modification,
63 are permitted provided that the following conditions are met:
64
65 * Redistributions of source code must retain the above copyright notice, this
66 list of conditions and the following disclaimer.
67 * Redistributions in binary form must reproduce the above copyright notice, this
68 list of conditions and the following disclaimer in the documentation and/or
69 other materials provided with the distribution.
70 * Neither the name of Intel Corporation nor the names of its contributors may
71 be used to endorse or promote products derived from this software without
72 specific prior written permission.
73
74 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
75 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
76 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
77 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
78 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
79 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
80 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
81 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
82 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
83 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
84 THE POSSIBILITY OF SUCH DAMAGE.
85
86 This file is automatically generated. Please do NOT modify !!!
87
88 **/
89 """
90
91 class CGenCfgOpt:
92 def __init__(self):
93 self.Error = ''
94
95 self._GlobalDataDef = """
96 GlobalDataDef
97 SKUID = 0, "DEFAULT"
98 EndGlobalData
99
100 """
101 self._BuidinOptionTxt = """
102 List &EN_DIS
103 Selection 0x1 , "Enabled"
104 Selection 0x0 , "Disabled"
105 EndList
106
107 """
108
109 self._BsfKeyList = ['FIND','NAME','HELP','TYPE','PAGE','OPTION','ORDER']
110 self._HdrKeyList = ['HEADER','STRUCT']
111 self._BuidinOption = {'$EN_DIS' : 'EN_DIS'}
112
113 self._MacroDict = {}
114 self._CfgBlkDict = {}
115 self._CfgPageDict = {}
116 self._CfgItemList = []
117 self._DscFile = ''
118 self._FvDir = ''
119 self._MapVer = 0
120
121 def ParseMacros (self, MacroDefStr):
122 # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']
123 self._MacroDict = {}
124 IsExpression = False
125 for Macro in MacroDefStr:
126 if Macro.startswith('-D'):
127 IsExpression = True
128 if len(Macro) > 2:
129 Macro = Macro[2:]
130 else :
131 continue
132 if IsExpression:
133 IsExpression = False
134 Match = re.match("(\w+)=(.+)", Macro)
135 if Match:
136 self._MacroDict[Match.group(1)] = Match.group(2)
137 else:
138 Match = re.match("(\w+)", Macro)
139 if Match:
140 self._MacroDict[Match.group(1)] = ''
141 if len(self._MacroDict) == 0:
142 self.Error = "Invalid MACRO arguments"
143 Error = 1
144 else:
145 Error = 0
146 return Error
147
148
149 def ParseDscFile (self, DscFile, FvDir):
150 self._CfgItemList = []
151 self._CfgPageDict = {}
152 self._CfgBlkDict = {}
153 self._DscFile = DscFile
154 self._FvDir = FvDir
155
156 IsDefSect = False
157 IsUpdSect = False
158 IsVpdSect = False
159 Found = False
160
161 IfStack = [True]
162 ElifStack = []
163 Error = 0
164
165 DscFd = open(DscFile, "r")
166 DscLines = DscFd.readlines()
167 DscFd.close()
168
169 ConfigDict = {}
170
171 for DscLine in DscLines:
172 Handle = False
173 DscLine = DscLine.strip()
174 Match = re.match("^\[(.+)\]", DscLine)
175 if Match is not None:
176 if Match.group(1).lower() == "Defines".lower():
177 IsDefSect = True
178 IsVpdSect = False
179 IsUpdSect = False
180 elif Match.group(1).lower() == "PcdsDynamicVpd".lower():
181 ConfigDict = {}
182 ConfigDict['header'] = 'ON'
183 ConfigDict['region'] = 'VPD'
184 ConfigDict['order'] = -1
185 ConfigDict['page'] = ''
186 ConfigDict['name'] = ''
187 ConfigDict['find'] = ''
188 ConfigDict['struct'] = ''
189 ConfigDict['subreg'] = []
190 IsDefSect = False
191 IsVpdSect = True
192 IsUpdSect = False
193 elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower():
194 ConfigDict = {}
195 ConfigDict['header'] = 'ON'
196 ConfigDict['region'] = 'UPD'
197 ConfigDict['order'] = -1
198 ConfigDict['page'] = ''
199 ConfigDict['name'] = ''
200 ConfigDict['find'] = ''
201 ConfigDict['struct'] = ''
202 ConfigDict['subreg'] = []
203 IsDefSect = False
204 IsUpdSect = True
205 IsVpdSect = False
206 Found = True
207 else:
208 IsDefSect = False
209 IsUpdSect = False
210 IsVpdSect = False
211 else:
212 if IsDefSect or IsUpdSect or IsVpdSect:
213 if DscLine == "!else":
214 IfStack[-1] = not IfStack[-1]
215 elif DscLine == "!endif":
216 IfStack.pop()
217 Level = ElifStack.pop()
218 while Level > 0:
219 IfStack.pop()
220 Level = Level - 1
221 else:
222 Result = False
223 Match = re.match("!(ifdef|ifndef)\s+\$\((\w+)\)", DscLine)
224 if Match is not None:
225 if Match.group(2) in self._MacroDict:
226 if Match.group(1) == 'ifdef':
227 Result = True
228 else:
229 if Match.group(1) == 'ifndef':
230 Result = True
231 ElifStack.append(0)
232 IfStack.append(Result)
233 else:
234 Match = re.match("!(if|elseif)\s+\$\\((\w+)\)\s*==\s*(\w+|\$\(\w+\))", DscLine)
235 if Match is not None:
236 if Match.group(2) in self._MacroDict:
237 MacroName = self._MacroDict[Match.group(2)]
238 else:
239 MacroName = ''
240 Value = Match.group(3)
241 if Value.startswith('$'):
242 if Value[2:-1] in self._MacroDict:
243 Value = self._MacroDict[Value[2:-1]]
244 else:
245 Value = ''
246 if MacroName == Value:
247 Result = True
248 if Match.group(1) == "if":
249 ElifStack.append(0)
250 IfStack.append(Result)
251 else: #elseif
252 IfStack[-1] = not IfStack[-1]
253 IfStack.append(Result)
254 ElifStack[-1] = ElifStack[-1] + 1
255 else:
256 if len(DscLine) > 0 and DscLine[0] == '!':
257 #
258 # Current it can only handle build switch.
259 # It does not support INF file in included dsc.
260 #
261 else:
262 if reduce(lambda x,y: x and y, IfStack):
263 Handle = True
264
265 if not Handle:
266 continue
267
268 if IsDefSect:
269 #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09
270 Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-\w]+)", DscLine)
271 if Match:
272 self._MacroDict[Match.group(1)] = Match.group(2)
273 else:
274 Match = re.match("^\s*#\s+!(BSF|HDR)\s+(.+)", DscLine)
275 if Match:
276 Remaining = Match.group(2)
277 if Match.group(1) == 'BSF':
278 Match = re.match("(?:^|.+\s+)PAGES:{(.+?)}", Remaining)
279 if Match:
280 # !BSF PAGES:{HSW:"Haswell System Agent", LPT:"Lynx Point PCH"}
281 PageList = Match.group(1).split(',')
282 for Page in PageList:
283 Page = Page.strip()
284 Match = re.match("(\w+):\"(.+)\"", Page)
285 self._CfgPageDict[Match.group(1)] = Match.group(2)
286
287 Match = re.match("(?:^|.+\s+)BLOCK:{NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*}", Remaining)
288 if Match:
289 self._CfgBlkDict['name'] = Match.group(1)
290 self._CfgBlkDict['ver'] = Match.group(2)
291
292 for Key in self._BsfKeyList:
293 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
294 if Match:
295 if Key in ['HELP', 'OPTION'] and Match.group(1).startswith('+'):
296 ConfigDict[Key.lower()] += Match.group(1)[1:]
297 else:
298 ConfigDict[Key.lower()] = Match.group(1)
299 else:
300 for Key in self._HdrKeyList:
301 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
302 if Match:
303 ConfigDict[Key.lower()] = Match.group(1)
304
305 # Check VPD/UPD
306 if IsUpdSect:
307 Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]{4})\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)
308 else:
309 Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)(?:\s*\|\s*(.+))?", DscLine)
310 if Match:
311 ConfigDict['space'] = Match.group(1)
312 ConfigDict['cname'] = Match.group(2)
313 ConfigDict['offset'] = int (Match.group(3), 16)
314 if ConfigDict['order'] == -1:
315 ConfigDict['order'] = ConfigDict['offset'] << 8
316 else:
317 (Major, Minor) = ConfigDict['order'].split('.')
318 ConfigDict['order'] = (int (Major, 16) << 8 ) + int (Minor, 16)
319 if IsUpdSect:
320 Value = Match.group(5).strip()
321 if Match.group(4).startswith("0x"):
322 Length = int (Match.group(4), 16)
323 else :
324 Length = int (Match.group(4))
325 else:
326 Value = Match.group(4)
327 if Value is None:
328 Value = ''
329 Value = Value.strip()
330 if '|' in Value:
331 Match = re.match("^.+\s*\|\s*(.+)", Value)
332 if Match:
333 Value = Match.group(1)
334 Length = -1
335
336 ConfigDict['length'] = Length
337 Match = re.match("\$\((\w+)\)", Value)
338 if Match:
339 if Match.group(1) in self._MacroDict:
340 Value = self._MacroDict[Match.group(1)]
341 ConfigDict['value'] = Value
342 if ConfigDict['name'] == '':
343 # Clear BSF specific items
344 ConfigDict['help'] = ''
345 ConfigDict['type'] = ''
346 ConfigDict['option'] = ''
347
348 self._CfgItemList.append(ConfigDict.copy())
349 ConfigDict['name'] = ''
350 ConfigDict['find'] = ''
351 ConfigDict['struct'] = ''
352 ConfigDict['order'] = -1
353 ConfigDict['subreg'] = []
354 else:
355 # It could be a virtual item as below
356 # !BSF FIELD:{1:SerialDebugPortAddress0}
357 Match = re.match("^\s*#\s+!BSF\s+FIELD:{(.+):(\d+)}", DscLine)
358 if Match:
359 SubCfgDict = ConfigDict
360 SubCfgDict['cname'] = Match.group(1)
361 SubCfgDict['length'] = int (Match.group(2))
362 if SubCfgDict['length'] > 0:
363 LastItem = self._CfgItemList[-1]
364 if len(LastItem['subreg']) == 0:
365 SubOffset = 0
366 else:
367 SubOffset += LastItem['subreg'][-1]['length']
368 SubCfgDict['offset'] = SubOffset
369 LastItem['subreg'].append (SubCfgDict.copy())
370 ConfigDict['name'] = ''
371 return Error
372
373 def UpdateSubRegionDefaultValue (self):
374 Error = 0
375 for Item in self._CfgItemList:
376 if len(Item['subreg']) == 0:
377 continue
378 bytearray = []
379 if Item['value'][0] == '{':
380 binlist = Item['value'][1:-1].split(',')
381 for each in binlist:
382 each = each.strip()
383 if each.startswith('0x'):
384 value = int(each, 16)
385 else:
386 value = int(each)
387 bytearray.append(value)
388 else:
389 if Item['value'].startswith('0x'):
390 value = int(Item['value'], 16)
391 else:
392 value = int(Item['value'])
393 idx = 0;
394 while idx < Item['length']:
395 bytearray.append(value & 0xFF)
396 value = value >> 8
397 idx = idx + 1
398 for SubItem in Item['subreg']:
399 if SubItem['length'] in (1,2,4,8):
400 valuelist = [b for b in bytearray[SubItem['offset']:SubItem['offset']+SubItem['length']]]
401 valuelist.reverse()
402 valuestr = "".join('%02X' % b for b in valuelist)
403 SubItem['value'] = '0x%s' % valuestr
404 else:
405 valuestr = ",".join('0x%02X' % b for b in bytearray[SubItem['offset']:SubItem['offset']+SubItem['length']])
406 SubItem['value'] = '{%s}' % valuestr
407 return Error
408
409 def UpdateVpdSizeField (self):
410 FvDir = self._FvDir;
411
412 if 'VPD_TOOL_GUID' not in self._MacroDict:
413 self.Error = "VPD_TOOL_GUID definition is missing in DSC file"
414 return 1
415
416 VpdMapFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + '.map')
417 if not os.path.exists(VpdMapFile):
418 self.Error = "VPD MAP file '%s' does not exist" % VpdMapFile
419 return 2
420
421 MapFd = open(VpdMapFile, "r")
422 MapLines = MapFd.readlines()
423 MapFd.close()
424
425 VpdDict = {}
426 PcdDict = {}
427 for MapLine in MapLines:
428 #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | DEFAULT | 0x0000 | 8 | 0x534450565F425346
429 #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | 0x0000 | 8 | 0x534450565F425346
430 #gPlatformFspPkgTokenSpaceGuid.PcdTest | 0x0008 | 5 | {0x01,0x02,0x03,0x04,0x05}
431 Match = re.match("([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)(\s\|\sDEFAULT)?\s\|\s(0x[0-9A-F]{4})\s\|\s(\d+|0x[0-9a-fA-F]+)\s\|\s(\{?[x0-9a-fA-F,\s]+\}?)", MapLine)
432 if Match:
433 Space = Match.group(1)
434 Name = Match.group(2)
435 if (self._MapVer == 0) and (Match.group(3) != None):
436 self._MapVer = 1
437 Offset = int (Match.group(4), 16)
438 if Match.group(5).startswith("0x"):
439 Length = int (Match.group(5), 16)
440 else :
441 Length = int (Match.group(5))
442 PcdDict["len"] = Length
443 PcdDict["value"] = Match.group(6)
444 VpdDict[Space+'.'+Name] = dict(PcdDict)
445
446 for Item in self._CfgItemList:
447 if Item['value'] == '':
448 Item['value'] = VpdDict[Item['space']+'.'+Item['cname']]['value']
449 if Item['length'] == -1:
450 Item['length'] = VpdDict[Item['space']+'.'+Item['cname']]['len']
451 if Item['struct'] != '':
452 Type = Item['struct'].strip()
453 if Type.endswith('*') and (Item['length'] != 4):
454 self.Error = "Struct pointer '%s' has invalid size" % Type
455 return 3
456
457 return 0
458
459 def CreateUpdTxtFile (self, UpdTxtFile):
460 FvDir = self._FvDir
461 if 'UPD_TOOL_GUID' not in self._MacroDict:
462 self.Error = "UPD_TOOL_GUID definition is missing in DSC file"
463 return 1
464
465 if UpdTxtFile == '':
466 UpdTxtFile = os.path.join(FvDir, self._MacroDict['UPD_TOOL_GUID'] + '.txt')
467
468 ReCreate = False
469 if not os.path.exists(UpdTxtFile):
470 ReCreate = True
471 else:
472 DscTime = os.path.getmtime(self._DscFile)
473 TxtTime = os.path.getmtime(UpdTxtFile)
474 if DscTime > TxtTime:
475 ReCreate = True
476
477 if not ReCreate:
478 # DSC has not been modified yet
479 # So don't have to re-generate other files
480 self.Error = 'No DSC file change, skip to create UPD TXT file'
481 return 256
482
483 TxtFd = open(UpdTxtFile, "w")
484 TxtFd.write("%s\n" % (__copyright_txt__ % date.today().year))
485
486 NextOffset = 0
487 SpaceIdx = 0
488 if self._MapVer == 1:
489 Default = 'DEFAULT|'
490 else:
491 Default = ''
492 for Item in self._CfgItemList:
493 if Item['region'] != 'UPD':
494 continue
495 Offset = Item['offset']
496 if NextOffset < Offset:
497 # insert one line
498 TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset, Offset - NextOffset))
499 SpaceIdx = SpaceIdx + 1
500 NextOffset = Offset + Item['length']
501 TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'],Item['length'],Item['value']))
502 TxtFd.close()
503 return 0
504
505 def CreateField (self, Name, Length, Offset, Struct):
506 PosName = 28
507 PosComment = 30
508
509 IsArray = False
510 if Length == 1:
511 Type = "UINT8"
512 elif Length == 2:
513 Type = "UINT16"
514 elif Length == 4:
515 Type = "UINT32"
516 elif Length == 8:
517 Type = "UINT64"
518 else:
519 Type = "UINT8"
520 IsArray = True
521
522 if Struct != '':
523 IsArray = False
524 Type = Struct
525
526 if IsArray:
527 Name = Name + '[%d]' % Length
528
529 if len(Type) < PosName:
530 Space1 = PosName - len(Type)
531 else:
532 Space1 = 1
533
534 if len(Name) < PosComment:
535 Space2 = PosComment - len(Name)
536 else:
537 Space2 = 1
538
539 return " %s%s%s;%s/* Offset 0x%04X */\n" % (Type, ' ' * Space1, Name, ' ' * Space2, Offset)
540
541
542 def CreateHeaderFile (self, InputHeaderFile, IsInternal):
543 Error = 0
544 FvDir = self._FvDir
545
546 if IsInternal:
547 HeaderFile = os.path.join(FvDir, 'VpdHeader.h')
548 else:
549 HeaderFile = os.path.join(FvDir, 'fsp_vpd.h')
550
551 # Check if header needs to be recreated
552 ReCreate = False
553 if IsInternal:
554 if not os.path.exists(HeaderFile):
555 ReCreate = True
556 else:
557 DscTime = os.path.getmtime(self._DscFile)
558 HeadTime = os.path.getmtime(HeaderFile)
559 if not os.path.exists(InputHeaderFile):
560 InpTime = HeadTime
561 else:
562 InpTime = os.path.getmtime(InputHeaderFile)
563 if DscTime > HeadTime or InpTime > HeadTime:
564 ReCreate = True
565
566 if not ReCreate:
567 self.Error = "No DSC or input header file is changed, skip the header file generating"
568 return 256
569
570 HeaderFd = open(HeaderFile, "w")
571 FileBase = os.path.basename(HeaderFile)
572 FileName = FileBase.replace(".", "_").upper()
573 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
574 HeaderFd.write("#ifndef __%s__\n" % FileName)
575 HeaderFd.write("#define __%s__\n\n" % FileName)
576 HeaderFd.write("#pragma pack(1)\n\n")
577
578 if InputHeaderFile != '':
579 if not os.path.exists(InputHeaderFile):
580 self.Error = "Input header file '%s' does not exist" % InputHeaderFile
581 return 2
582
583 InFd = open(InputHeaderFile, "r")
584 IncLines = InFd.readlines()
585 InFd.close()
586
587 Export = False
588 for Line in IncLines:
589 Match = re.search ("!EXPORT\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line)
590 if Match:
591 if Match.group(1) == "BEGIN":
592 Export = True
593 continue
594 else:
595 Export = False
596 continue
597 if Export:
598 HeaderFd.write(Line)
599 HeaderFd.write("\n\n")
600
601 for Region in ['UPD', 'VPD']:
602
603 # Write PcdVpdRegionSign and PcdImageRevision
604 if Region[0] == 'V':
605 if 'VPD_TOOL_GUID' not in self._MacroDict:
606 self.Error = "VPD_TOOL_GUID definition is missing in DSC file"
607 Error = 1
608 break
609
610 BinFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + ".bin")
611 if not os.path.exists(BinFile):
612 self.Error = "VPD binary file '%s' does not exist" % BinFile
613 Error = 2
614 break
615
616 BinFd = open(BinFile, "rb")
617 IdStr = BinFd.read(0x08)
618 ImageId = struct.unpack('<Q', IdStr)
619 ImageRev = struct.unpack('<I', BinFd.read(0x04))
620 BinFd.close()
621
622 HeaderFd.write("#define VPD_IMAGE_ID 0x%016X /* '%s' */\n" % (ImageId[0], IdStr))
623 HeaderFd.write("#define VPD_IMAGE_REV 0x%08X \n\n" % ImageRev[0])
624
625 HeaderFd.write("typedef struct _" + Region[0] + "PD_DATA_REGION {\n")
626 NextOffset = 0
627 SpaceIdx = 0
628 Offset = 0
629
630 LastVisible = True
631 ResvOffset = 0
632 ResvIdx = 0
633 LineBuffer = []
634 for Item in self._CfgItemList:
635 if Item['region'] != Region:
636 continue
637
638 NextVisible = LastVisible
639 if not IsInternal:
640 if LastVisible and (Item['header'] == 'OFF'):
641 NextVisible = False
642 ResvOffset = Item['offset']
643 elif (not LastVisible) and Item['header'] == 'ON':
644 NextVisible = True
645 Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx
646 ResvIdx = ResvIdx + 1
647 HeaderFd.write(self.CreateField (Name, Item["offset"] - ResvOffset, ResvOffset, ''))
648
649 if Offset < Item["offset"]:
650 if IsInternal or LastVisible:
651 Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx
652 LineBuffer.append(self.CreateField (Name, Item["offset"] - Offset, Offset, ''))
653 SpaceIdx = SpaceIdx + 1
654 Offset = Item["offset"]
655
656 if Offset != Item["offset"]:
657 print "Unsorted offset 0x%04X\n" % Item["offset"]
658 error = 2
659 break;
660
661 LastVisible = NextVisible
662
663 Offset = Offset + Item["length"]
664 if IsInternal or LastVisible:
665 for Each in LineBuffer:
666 HeaderFd.write (Each)
667 LineBuffer = []
668 HeaderFd.write(self.CreateField (Item["cname"], Item["length"], Item["offset"], Item['struct']))
669
670 HeaderFd.write("} " + Region[0] + "PD_DATA_REGION;\n\n")
671 HeaderFd.write("#pragma pack()\n\n")
672 HeaderFd.write("#endif\n")
673 HeaderFd.close()
674
675 return Error
676
677 def WriteBsfStruct (self, BsfFd, Item):
678 if Item['type'] == "None":
679 Space = "gPlatformFspPkgTokenSpaceGuid"
680 else:
681 Space = Item['space']
682 Line = " $%s_%s" % (Space, Item['cname'])
683 Match = re.match("\s*\{([x0-9a-fA-F,\s]+)\}\s*", Item['value'])
684 if Match:
685 DefaultValue = Match.group(1).strip()
686 else:
687 DefaultValue = Item['value'].strip()
688 BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue))
689 TmpList = []
690 if Item['type'] == "Combo":
691 if not Item['option'] in self._BuidinOption:
692 OptList = Item['option'].split(',')
693 for Option in OptList:
694 Option = Option.strip()
695 (OpVal, OpStr) = Option.split(':')
696 TmpList.append((OpVal, OpStr))
697 return TmpList
698
699 def WriteBsfOption (self, BsfFd, Item):
700 PcdName = Item['space'] + '_' + Item['cname']
701 WriteHelp = 0
702 if Item['type'] == "Combo":
703 if Item['option'] in self._BuidinOption:
704 Options = self._BuidinOption[Item['option']]
705 else:
706 Options = PcdName
707 BsfFd.write(' %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options));
708 WriteHelp = 1
709 elif Item['type'].startswith("EditNum"):
710 Match = re.match("EditNum\s*,\s*(HEX|DEC)\s*,\s*\((\d+|0x[0-9A-Fa-f]+)\s*,\s*(\d+|0x[0-9A-Fa-f]+)\)", Item['type'])
711 if Match:
712 BsfFd.write(' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1)));
713 WriteHelp = 2
714 elif Item['type'].startswith("EditText"):
715 BsfFd.write(' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name']));
716 WriteHelp = 1
717
718 if WriteHelp > 0:
719 HelpLines = Item['help'].split('\\n\\r')
720 FirstLine = True
721 for HelpLine in HelpLines:
722 if FirstLine:
723 FirstLine = False
724 BsfFd.write(' Help "%s"\n' % (HelpLine));
725 else:
726 BsfFd.write(' "%s"\n' % (HelpLine));
727 if WriteHelp == 2:
728 BsfFd.write(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3)));
729
730 def GenerateBsfFile (self, BsfFile):
731
732 if BsfFile == '':
733 self.Error = "BSF output file '%s' is invalid" % BsfFile
734 return 1
735
736 Error = 0
737 OptionDict = {}
738 BsfFd = open(BsfFile, "w")
739 BsfFd.write("%s\n" % (__copyright_bsf__ % date.today().year))
740 BsfFd.write("%s\n" % self._GlobalDataDef);
741 BsfFd.write("StructDef\n")
742 NextOffset = -1
743 for Item in self._CfgItemList:
744 if Item['find'] != '':
745 BsfFd.write('\n Find "%s"\n' % Item['find'])
746 NextOffset = Item['offset'] + Item['length']
747 if Item['name'] != '':
748 if NextOffset != Item['offset']:
749 BsfFd.write(" Skip %d bytes\n" % (Item['offset'] - NextOffset))
750 if len(Item['subreg']) > 0:
751 NextOffset = Item['offset']
752 for SubItem in Item['subreg']:
753 NextOffset += SubItem['length']
754 if SubItem['name'] == '':
755 BsfFd.write(" Skip %d bytes\n" % (SubItem['length']))
756 else:
757 Options = self.WriteBsfStruct(BsfFd, SubItem)
758 if len(Options) > 0:
759 OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options
760 if (Item['offset'] + Item['length']) < NextOffset:
761 self.Error = "BSF sub region '%s' length does not match" % (Item['space']+'.'+Item['cname'])
762 return 2
763 else:
764 NextOffset = Item['offset'] + Item['length']
765 Options = self.WriteBsfStruct(BsfFd, Item)
766 if len(Options) > 0:
767 OptionDict[Item['space']+'_'+Item['cname']] = Options
768 BsfFd.write("\nEndStruct\n\n")
769
770 BsfFd.write("%s" % self._BuidinOptionTxt);
771
772 for Each in OptionDict:
773 BsfFd.write("List &%s\n" % Each);
774 for Item in OptionDict[Each]:
775 BsfFd.write(' Selection %s , "%s"\n' % (Item[0], Item[1]));
776 BsfFd.write("EndList\n\n");
777
778 BsfFd.write("BeginInfoBlock\n");
779 BsfFd.write(' PPVer "%s"\n' % (self._CfgBlkDict['ver']));
780 BsfFd.write(' Description "%s"\n' % (self._CfgBlkDict['name']));
781 BsfFd.write("EndInfoBlock\n\n");
782
783 for Each in self._CfgPageDict:
784 BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each]);
785 BsfItems = []
786 for Item in self._CfgItemList:
787 if Item['name'] != '':
788 if Item['page'] != Each:
789 continue
790 if len(Item['subreg']) > 0:
791 for SubItem in Item['subreg']:
792 if SubItem['name'] != '':
793 BsfItems.append(SubItem)
794 else:
795 BsfItems.append(Item)
796
797 BsfItems.sort(key=lambda x: x['order'])
798
799 for Item in BsfItems:
800 self.WriteBsfOption (BsfFd, Item)
801 BsfFd.write("EndPage\n\n");
802
803 BsfFd.close()
804 return Error
805
806
807 def Usage():
808 print "GenCfgOpt Version 0.50"
809 print "Usage:"
810 print " GenCfgOpt UPDTXT PlatformDscFile BuildFvDir [TxtOutFile] [-D Macros]"
811 print " GenCfgOpt HEADER PlatformDscFile BuildFvDir [InputHFile] [-D Macros]"
812 print " GenCfgOpt GENBSF PlatformDscFile BuildFvDir BsfOutFile [-D Macros]"
813
814 def Main():
815 #
816 # Parse the options and args
817 #
818 GenCfgOpt = CGenCfgOpt()
819 argc = len(sys.argv)
820 if argc < 4:
821 Usage()
822 return 1
823 else:
824 DscFile = sys.argv[2]
825 if not os.path.exists(DscFile):
826 print "ERROR: Cannot open DSC file '%s' !" % DscFile
827 return 2
828
829 OutFile = ''
830 if argc > 4:
831 if sys.argv[4][0] == '-':
832 Start = 4
833 else:
834 OutFile = sys.argv[4]
835 Start = 5
836 if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:
837 print "ERROR: %s !" % GenCfgOpt.Error
838 return 3
839
840 FvDir = sys.argv[3]
841 if not os.path.isdir(FvDir):
842 print "ERROR: FV folder '%s' is invalid !" % FvDir
843 return 4
844
845 if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:
846 print "ERROR: %s !" % GenCfgOpt.Error
847 return 5
848
849
850 if GenCfgOpt.UpdateVpdSizeField() != 0:
851 print "ERROR: %s !" % GenCfgOpt.Error
852 return 6
853
854 if GenCfgOpt.UpdateSubRegionDefaultValue() != 0:
855 print "ERROR: %s !" % GenCfgOpt.Error
856 return 7
857
858 if sys.argv[1] == "UPDTXT":
859 Ret = GenCfgOpt.CreateUpdTxtFile(OutFile)
860 if Ret != 0:
861 # No change is detected
862 if Ret == 256:
863 print "INFO: %s !" % (GenCfgOpt.Error)
864 else :
865 print "ERROR: %s !" % (GenCfgOpt.Error)
866 return Ret
867 elif sys.argv[1] == "HEADER":
868 Ret = GenCfgOpt.CreateHeaderFile(OutFile, True)
869 if Ret != 0:
870 # No change is detected
871 if Ret == 256:
872 print "INFO: %s !" % (GenCfgOpt.Error)
873 else :
874 print "ERROR: %s !" % (GenCfgOpt.Error)
875 return Ret
876 if GenCfgOpt.CreateHeaderFile(OutFile, False) != 0:
877 print "ERROR: %s !" % GenCfgOpt.Error
878 return 8
879 elif sys.argv[1] == "GENBSF":
880 if GenCfgOpt.GenerateBsfFile(OutFile) != 0:
881 print "ERROR: %s !" % GenCfgOpt.Error
882 return 9
883 else:
884 if argc < 5:
885 Usage()
886 return 1
887 print "ERROR: Unknown command '%s' !" % sys.argv[1]
888 Usage()
889 return 1
890 return 0
891 return 0
892
893
894 if __name__ == '__main__':
895 sys.exit(Main())