]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFspPkg/Tools/GenCfgOpt.py
Replace SetPower2 by EDKII baselib - GetPowerOfTwo64.
[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 CLogicalExpression:
92 def __init__(self):
93 self.index = 0
94 self.string = ''
95
96 def errExit(self, err = ''):
97 print "ERROR: Express parsing for:"
98 print " %s" % self.string
99 print " %s^" % (' ' * self.index)
100 if err:
101 print "INFO : %s" % err
102 raise SystemExit
103
104 def getNonNumber (self, n1, n2):
105 if not n1.isdigit():
106 return n1
107 if not n2.isdigit():
108 return n2
109 return None
110
111 def getCurr(self, lens = 1):
112 try:
113 if lens == -1:
114 return self.string[self.index :]
115 else:
116 if self.index + lens > len(self.string):
117 lens = len(self.string) - self.index
118 return self.string[self.index : self.index + lens]
119 except Exception:
120 return ''
121
122 def isLast(self):
123 return self.index == len(self.string)
124
125 def moveNext(self, len = 1):
126 self.index += len
127
128 def skipSpace(self):
129 while not self.isLast():
130 if self.getCurr() in ' \t':
131 self.moveNext()
132 else:
133 return
134
135 def normNumber (self, val):
136 return True if val else False
137
138 def getNumber(self, var):
139 var = var.strip()
140 if re.match('^0x[a-fA-F0-9]+$', var):
141 value = int(var, 16)
142 elif re.match('^[+-]?\d+$', var):
143 value = int(var, 10)
144 else:
145 value = None
146 return value
147
148 def parseValue(self):
149 self.skipSpace()
150 var = ''
151 while not self.isLast():
152 char = self.getCurr()
153 if re.match('^[\w.]', char):
154 var += char
155 self.moveNext()
156 else:
157 break
158 val = self.getNumber(var)
159 if val is None:
160 value = var
161 else:
162 value = "%d" % val
163 return value
164
165 def parseSingleOp(self):
166 self.skipSpace()
167 if re.match('^NOT\W', self.getCurr(-1)):
168 self.moveNext(3)
169 op = self.parseBrace()
170 val = self.getNumber (op)
171 if val is None:
172 self.errExit ("'%s' is not a number" % op)
173 return "%d" % (not self.normNumber(int(op)))
174 else:
175 return self.parseValue()
176
177 def parseBrace(self):
178 self.skipSpace()
179 char = self.getCurr()
180 if char == '(':
181 self.moveNext()
182 value = self.parseExpr()
183 self.skipSpace()
184 if self.getCurr() != ')':
185 self.errExit ("Expecting closing brace or operator")
186 self.moveNext()
187 return value
188 else:
189 value = self.parseSingleOp()
190 return value
191
192 def parseCompare(self):
193 value = self.parseBrace()
194 while True:
195 self.skipSpace()
196 char = self.getCurr()
197 if char in ['<', '>']:
198 self.moveNext()
199 next = self.getCurr()
200 if next == '=':
201 op = char + next
202 self.moveNext()
203 else:
204 op = char
205 result = self.parseBrace()
206 test = self.getNonNumber(result, value)
207 if test is None:
208 value = "%d" % self.normNumber(eval (value + op + result))
209 else:
210 self.errExit ("'%s' is not a valid number for comparision" % test)
211 elif char in ['=', '!']:
212 op = self.getCurr(2)
213 if op in ['==', '!=']:
214 self.moveNext(2)
215 result = self.parseBrace()
216 test = self.getNonNumber(result, value)
217 if test is None:
218 value = "%d" % self.normNumber((eval (value + op + result)))
219 else:
220 value = "%d" % self.normNumber(eval ("'" + value + "'" + op + "'" + result + "'"))
221 else:
222 break
223 else:
224 break
225 return value
226
227 def parseAnd(self):
228 value = self.parseCompare()
229 while True:
230 self.skipSpace()
231 if re.match('^AND\W', self.getCurr(-1)):
232 self.moveNext(3)
233 result = self.parseCompare()
234 test = self.getNonNumber(result, value)
235 if test is None:
236 value = "%d" % self.normNumber(int(value) & int(result))
237 else:
238 self.errExit ("'%s' is not a valid op number for AND" % test)
239 else:
240 break
241 return value
242
243 def parseOrXor(self):
244 value = self.parseAnd()
245 op = None
246 while True:
247 self.skipSpace()
248 op = None
249 if re.match('^XOR\W', self.getCurr(-1)):
250 self.moveNext(3)
251 op = '^'
252 elif re.match('^OR\W', self.getCurr(-1)):
253 self.moveNext(2)
254 op = '|'
255 else:
256 break
257 if op:
258 result = self.parseAnd()
259 test = self.getNonNumber(result, value)
260 if test is None:
261 value = "%d" % self.normNumber(eval (value + op + result))
262 else:
263 self.errExit ("'%s' is not a valid op number for XOR/OR" % test)
264 return value
265
266 def parseExpr(self):
267 return self.parseOrXor()
268
269 def getResult(self):
270 value = self.parseExpr()
271 self.skipSpace()
272 if not self.isLast():
273 self.errExit ("Unexpected character found '%s'" % self.getCurr())
274 test = self.getNumber(value)
275 if test is None:
276 self.errExit ("Result '%s' is not a number" % value)
277 return int(value)
278
279 def evaluateExpress (self, Expr):
280 self.index = 0
281 self.string = Expr
282 if self.getResult():
283 Result = True
284 else:
285 Result = False
286 return Result
287
288 class CGenCfgOpt:
289 def __init__(self):
290 self.Debug = False
291 self.Error = ''
292
293 self._GlobalDataDef = """
294 GlobalDataDef
295 SKUID = 0, "DEFAULT"
296 EndGlobalData
297
298 """
299 self._BuidinOptionTxt = """
300 List &EN_DIS
301 Selection 0x1 , "Enabled"
302 Selection 0x0 , "Disabled"
303 EndList
304
305 """
306
307 self._BsfKeyList = ['FIND','NAME','HELP','TYPE','PAGE','OPTION','ORDER']
308 self._HdrKeyList = ['HEADER','STRUCT']
309 self._BuidinOption = {'$EN_DIS' : 'EN_DIS'}
310
311 self._MacroDict = {}
312 self._CfgBlkDict = {}
313 self._CfgPageDict = {}
314 self._CfgItemList = []
315 self._DscFile = ''
316 self._FvDir = ''
317 self._MapVer = 0
318
319 def ParseMacros (self, MacroDefStr):
320 # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']
321 self._MacroDict = {}
322 IsExpression = False
323 for Macro in MacroDefStr:
324 if Macro.startswith('-D'):
325 IsExpression = True
326 if len(Macro) > 2:
327 Macro = Macro[2:]
328 else :
329 continue
330 if IsExpression:
331 IsExpression = False
332 Match = re.match("(\w+)=(.+)", Macro)
333 if Match:
334 self._MacroDict[Match.group(1)] = Match.group(2)
335 else:
336 Match = re.match("(\w+)", Macro)
337 if Match:
338 self._MacroDict[Match.group(1)] = ''
339 if len(self._MacroDict) == 0:
340 Error = 1
341 else:
342 Error = 0
343 if self.Debug:
344 print "INFO : Macro dictionary:"
345 for Each in self._MacroDict:
346 print " $(%s) = [ %s ]" % (Each , self._MacroDict[Each])
347 return Error
348
349 def EvaulateIfdef (self, Macro):
350 Result = Macro in self._MacroDict
351 if self.Debug:
352 print "INFO : Eval Ifdef [%s] : %s" % (Macro, Result)
353 return Result
354
355 def ExpandMacros (self, Input):
356 Line = Input
357 Match = re.findall("\$\(\w+\)", Input)
358 if Match:
359 for Each in Match:
360 Variable = Each[2:-1]
361 if Variable in self._MacroDict:
362 Line = Line.replace(Each, self._MacroDict[Variable])
363 else:
364 if self.Debug:
365 print "WARN : %s is not defined" % Each
366 Line = Line.replace(Each, Each[2:-1])
367 return Line
368
369 def EvaluateExpress (self, Expr):
370 ExpExpr = self.ExpandMacros(Expr)
371 LogExpr = CLogicalExpression()
372 Result = LogExpr.evaluateExpress (ExpExpr)
373 if self.Debug:
374 print "INFO : Eval Express [%s] : %s" % (Expr, Result)
375 return Result
376
377 def FormatListValue(self, ConfigDict):
378 Struct = ConfigDict['struct']
379 if Struct not in ['UINT8','UINT16','UINT32','UINT64']:
380 return
381
382 dataarray = []
383 binlist = ConfigDict['value'][1:-1].split(',')
384 for each in binlist:
385 each = each.strip()
386 if each.startswith('0x'):
387 value = int(each, 16)
388 else:
389 value = int(each)
390 dataarray.append(value)
391
392 unit = int(Struct[4:]) / 8
393 if int(ConfigDict['length']) != unit * len(dataarray):
394 raise Exception("Array size is not proper for '%s' !" % ConfigDict['cname'])
395
396 bytearray = []
397 for each in dataarray:
398 value = each
399 for loop in xrange(unit):
400 bytearray.append("0x%02X" % (value & 0xFF))
401 value = value >> 8
402 newvalue = '{' + ','.join(bytearray) + '}'
403 ConfigDict['value'] = newvalue
404 return ""
405
406 def ParseDscFile (self, DscFile, FvDir):
407 self._CfgItemList = []
408 self._CfgPageDict = {}
409 self._CfgBlkDict = {}
410 self._DscFile = DscFile
411 self._FvDir = FvDir
412
413 IsDefSect = False
414 IsUpdSect = False
415 IsVpdSect = False
416 Found = False
417
418 IfStack = []
419 ElifStack = []
420 Error = 0
421 ConfigDict = {}
422
423 DscFd = open(DscFile, "r")
424 DscLines = DscFd.readlines()
425 DscFd.close()
426
427 while len(DscLines):
428 DscLine = DscLines.pop(0).strip()
429 Handle = False
430 Match = re.match("^\[(.+)\]", DscLine)
431 if Match is not None:
432 if Match.group(1).lower() == "Defines".lower():
433 IsDefSect = True
434 IsVpdSect = False
435 IsUpdSect = False
436 elif Match.group(1).lower() == "PcdsDynamicVpd".lower():
437 ConfigDict = {}
438 ConfigDict['header'] = 'ON'
439 ConfigDict['region'] = 'VPD'
440 ConfigDict['order'] = -1
441 ConfigDict['page'] = ''
442 ConfigDict['name'] = ''
443 ConfigDict['find'] = ''
444 ConfigDict['struct'] = ''
445 ConfigDict['subreg'] = []
446 IsDefSect = False
447 IsVpdSect = True
448 IsUpdSect = False
449 elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower():
450 ConfigDict = {}
451 ConfigDict['header'] = 'ON'
452 ConfigDict['region'] = 'UPD'
453 ConfigDict['order'] = -1
454 ConfigDict['page'] = ''
455 ConfigDict['name'] = ''
456 ConfigDict['find'] = ''
457 ConfigDict['struct'] = ''
458 ConfigDict['subreg'] = []
459 IsDefSect = False
460 IsUpdSect = True
461 IsVpdSect = False
462 Found = True
463 else:
464 IsDefSect = False
465 IsUpdSect = False
466 IsVpdSect = False
467 else:
468 if IsDefSect or IsUpdSect or IsVpdSect:
469 if re.match("^!else($|\s+#.+)", DscLine):
470 if IfStack:
471 IfStack[-1] = not IfStack[-1]
472 else:
473 print("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine)
474 raise SystemExit
475 elif re.match("^!endif($|\s+#.+)", DscLine):
476 if IfStack:
477 IfStack.pop()
478 Level = ElifStack.pop()
479 if Level > 0:
480 del IfStack[-Level:]
481 else:
482 print("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine)
483 raise SystemExit
484 else:
485 Result = False
486 Match = re.match("!(ifdef|ifndef)\s+(.+)", DscLine)
487 if Match:
488 Result = self.EvaulateIfdef (Match.group(2))
489 if Match.group(1) == 'ifndef':
490 Result = not Result
491 IfStack.append(Result)
492 ElifStack.append(0)
493 else:
494 Match = re.match("!(if|elseif)\s+(.+)", DscLine)
495 if Match:
496 Result = self.EvaluateExpress(Match.group(2))
497 if Match.group(1) == "if":
498 ElifStack.append(0)
499 IfStack.append(Result)
500 else: #elseif
501 if IfStack:
502 IfStack[-1] = not IfStack[-1]
503 IfStack.append(Result)
504 ElifStack[-1] = ElifStack[-1] + 1
505 else:
506 print("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine)
507 raise SystemExit
508 else:
509 if IfStack:
510 Handle = reduce(lambda x,y: x and y, IfStack)
511 else:
512 Handle = True
513 if Handle:
514 Match = re.match("!include\s+(.+)", DscLine)
515 if Match:
516 IncludeFilePath = Match.group(1)
517 IncludeFilePath = self.ExpandMacros(IncludeFilePath)
518 try:
519 IncludeDsc = open(IncludeFilePath, "r")
520 except:
521 print("ERROR: Cannot open file '%s'" % IncludeFilePath)
522 raise SystemExit
523 NewDscLines = IncludeDsc.readlines()
524 IncludeDsc.close()
525 DscLines = NewDscLines + DscLines
526 else:
527 if DscLine.startswith('!'):
528 print("ERROR: Unrecoginized directive for line '%s'" % DscLine)
529 raise SystemExit
530
531 if not Handle:
532 continue
533
534 if IsDefSect:
535 #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09
536 Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-.\w]+)", DscLine)
537 if Match:
538 self._MacroDict[Match.group(1)] = Match.group(2)
539 if self.Debug:
540 print "INFO : DEFINE %s = [ %s ]" % (Match.group(1), Match.group(2))
541 else:
542 Match = re.match("^\s*#\s+!(BSF|HDR)\s+(.+)", DscLine)
543 if Match:
544 Remaining = Match.group(2)
545 if Match.group(1) == 'BSF':
546 Match = re.match("(?:^|.+\s+)PAGES:{(.+?)}", Remaining)
547 if Match:
548 # !BSF PAGES:{HSW:"Haswell System Agent", LPT:"Lynx Point PCH"}
549 PageList = Match.group(1).split(',')
550 for Page in PageList:
551 Page = Page.strip()
552 Match = re.match("(\w+):\"(.+)\"", Page)
553 self._CfgPageDict[Match.group(1)] = Match.group(2)
554
555 Match = re.match("(?:^|.+\s+)BLOCK:{NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*}", Remaining)
556 if Match:
557 self._CfgBlkDict['name'] = Match.group(1)
558 self._CfgBlkDict['ver'] = Match.group(2)
559
560 for Key in self._BsfKeyList:
561 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
562 if Match:
563 if Key in ['HELP', 'OPTION'] and Match.group(1).startswith('+'):
564 ConfigDict[Key.lower()] += Match.group(1)[1:]
565 else:
566 ConfigDict[Key.lower()] = Match.group(1)
567 else:
568 for Key in self._HdrKeyList:
569 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
570 if Match:
571 ConfigDict[Key.lower()] = Match.group(1)
572
573 # Check VPD/UPD
574 if IsUpdSect:
575 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)
576 else:
577 Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)(?:\s*\|\s*(.+))?", DscLine)
578 if Match:
579 ConfigDict['space'] = Match.group(1)
580 ConfigDict['cname'] = Match.group(2)
581 ConfigDict['offset'] = int (Match.group(3), 16)
582 if ConfigDict['order'] == -1:
583 ConfigDict['order'] = ConfigDict['offset'] << 8
584 else:
585 (Major, Minor) = ConfigDict['order'].split('.')
586 ConfigDict['order'] = (int (Major, 16) << 8 ) + int (Minor, 16)
587 if IsUpdSect:
588 Value = Match.group(5).strip()
589 if Match.group(4).startswith("0x"):
590 Length = int (Match.group(4), 16)
591 else :
592 Length = int (Match.group(4))
593 else:
594 Value = Match.group(4)
595 if Value is None:
596 Value = ''
597 Value = Value.strip()
598 if '|' in Value:
599 Match = re.match("^.+\s*\|\s*(.+)", Value)
600 if Match:
601 Value = Match.group(1)
602 Length = -1
603
604 ConfigDict['length'] = Length
605 Match = re.match("\$\((\w+)\)", Value)
606 if Match:
607 if Match.group(1) in self._MacroDict:
608 Value = self._MacroDict[Match.group(1)]
609
610 ConfigDict['value'] = Value
611 if (len(Value) > 0) and (Value[0] == '{'):
612 Value = self.FormatListValue(ConfigDict)
613
614 if ConfigDict['name'] == '':
615 # Clear BSF specific items
616 ConfigDict['help'] = ''
617 ConfigDict['type'] = ''
618 ConfigDict['option'] = ''
619
620 self._CfgItemList.append(ConfigDict.copy())
621 ConfigDict['name'] = ''
622 ConfigDict['find'] = ''
623 ConfigDict['struct'] = ''
624 ConfigDict['order'] = -1
625 ConfigDict['subreg'] = []
626 else:
627 # It could be a virtual item as below
628 # !BSF FIELD:{1:SerialDebugPortAddress0}
629 Match = re.match("^\s*#\s+!BSF\s+FIELD:{(.+):(\d+)}", DscLine)
630 if Match:
631 SubCfgDict = ConfigDict
632 SubCfgDict['cname'] = Match.group(1)
633 SubCfgDict['length'] = int (Match.group(2))
634 if SubCfgDict['length'] > 0:
635 LastItem = self._CfgItemList[-1]
636 if len(LastItem['subreg']) == 0:
637 SubOffset = 0
638 else:
639 SubOffset += LastItem['subreg'][-1]['length']
640 SubCfgDict['offset'] = SubOffset
641 LastItem['subreg'].append (SubCfgDict.copy())
642 ConfigDict['name'] = ''
643 return Error
644
645 def UpdateSubRegionDefaultValue (self):
646 Error = 0
647 for Item in self._CfgItemList:
648 if len(Item['subreg']) == 0:
649 continue
650 bytearray = []
651 if Item['value'][0] == '{':
652 binlist = Item['value'][1:-1].split(',')
653 for each in binlist:
654 each = each.strip()
655 if each.startswith('0x'):
656 value = int(each, 16)
657 else:
658 value = int(each)
659 bytearray.append(value)
660 else:
661 if Item['value'].startswith('0x'):
662 value = int(Item['value'], 16)
663 else:
664 value = int(Item['value'])
665 idx = 0;
666 while idx < Item['length']:
667 bytearray.append(value & 0xFF)
668 value = value >> 8
669 idx = idx + 1
670 for SubItem in Item['subreg']:
671 if SubItem['length'] in (1,2,4,8):
672 valuelist = [b for b in bytearray[SubItem['offset']:SubItem['offset']+SubItem['length']]]
673 valuelist.reverse()
674 valuestr = "".join('%02X' % b for b in valuelist)
675 SubItem['value'] = '0x%s' % valuestr
676 else:
677 valuestr = ",".join('0x%02X' % b for b in bytearray[SubItem['offset']:SubItem['offset']+SubItem['length']])
678 SubItem['value'] = '{%s}' % valuestr
679 return Error
680
681 def UpdateVpdSizeField (self):
682 FvDir = self._FvDir;
683
684 if 'VPD_TOOL_GUID' not in self._MacroDict:
685 self.Error = "VPD_TOOL_GUID definition is missing in DSC file"
686 return 1
687
688 VpdMapFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + '.map')
689 if not os.path.exists(VpdMapFile):
690 self.Error = "VPD MAP file '%s' does not exist" % VpdMapFile
691 return 2
692
693 MapFd = open(VpdMapFile, "r")
694 MapLines = MapFd.readlines()
695 MapFd.close()
696
697 VpdDict = {}
698 PcdDict = {}
699 for MapLine in MapLines:
700 #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | DEFAULT | 0x0000 | 8 | 0x534450565F425346
701 #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | 0x0000 | 8 | 0x534450565F425346
702 #gPlatformFspPkgTokenSpaceGuid.PcdTest | 0x0008 | 5 | {0x01,0x02,0x03,0x04,0x05}
703 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)
704 if Match:
705 Space = Match.group(1)
706 Name = Match.group(2)
707 if (self._MapVer == 0) and (Match.group(3) != None):
708 self._MapVer = 1
709 Offset = int (Match.group(4), 16)
710 if Match.group(5).startswith("0x"):
711 Length = int (Match.group(5), 16)
712 else :
713 Length = int (Match.group(5))
714 PcdDict["len"] = Length
715 PcdDict["value"] = Match.group(6)
716 VpdDict[Space+'.'+Name] = dict(PcdDict)
717
718 for Item in self._CfgItemList:
719 if Item['value'] == '':
720 Item['value'] = VpdDict[Item['space']+'.'+Item['cname']]['value']
721 if Item['length'] == -1:
722 Item['length'] = VpdDict[Item['space']+'.'+Item['cname']]['len']
723 if Item['struct'] != '':
724 Type = Item['struct'].strip()
725 if Type.endswith('*') and (Item['length'] != 4):
726 self.Error = "Struct pointer '%s' has invalid size" % Type
727 return 3
728
729 return 0
730
731 def CreateUpdTxtFile (self, UpdTxtFile):
732 FvDir = self._FvDir
733 if 'UPD_TOOL_GUID' not in self._MacroDict:
734 self.Error = "UPD_TOOL_GUID definition is missing in DSC file"
735 return 1
736
737 if UpdTxtFile == '':
738 UpdTxtFile = os.path.join(FvDir, self._MacroDict['UPD_TOOL_GUID'] + '.txt')
739
740 ReCreate = False
741 if not os.path.exists(UpdTxtFile):
742 ReCreate = True
743 else:
744 DscTime = os.path.getmtime(self._DscFile)
745 TxtTime = os.path.getmtime(UpdTxtFile)
746 if DscTime > TxtTime:
747 ReCreate = True
748
749 if not ReCreate:
750 # DSC has not been modified yet
751 # So don't have to re-generate other files
752 self.Error = 'No DSC file change, skip to create UPD TXT file'
753 return 256
754
755 TxtFd = open(UpdTxtFile, "w")
756 TxtFd.write("%s\n" % (__copyright_txt__ % date.today().year))
757
758 NextOffset = 0
759 SpaceIdx = 0
760 if self._MapVer == 1:
761 Default = 'DEFAULT|'
762 else:
763 Default = ''
764 for Item in self._CfgItemList:
765 if Item['region'] != 'UPD':
766 continue
767 Offset = Item['offset']
768 if NextOffset < Offset:
769 # insert one line
770 TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset, Offset - NextOffset))
771 SpaceIdx = SpaceIdx + 1
772 NextOffset = Offset + Item['length']
773 TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'],Item['length'],Item['value']))
774 TxtFd.close()
775 return 0
776
777 def CreateField (self, Item, Name, Length, Offset, Struct):
778 PosName = 28
779 PosComment = 30
780
781 IsArray = False
782 if Length in [1,2,4,8]:
783 Type = "UINT%d" % (Length * 8)
784 else:
785 IsArray = True
786 Type = "UINT8"
787
788 if Item['value'].startswith('{'):
789 Type = "UINT8"
790 IsArray = True
791
792 if Struct != '':
793 Type = Struct
794 if Struct in ['UINT8','UINT16','UINT32','UINT64']:
795 IsArray = True
796 Unit = int(Type[4:]) / 8
797 Length = Length / Unit
798 else:
799 IsArray = False
800
801 if IsArray:
802 Name = Name + '[%d]' % Length
803
804 if len(Type) < PosName:
805 Space1 = PosName - len(Type)
806 else:
807 Space1 = 1
808
809 if len(Name) < PosComment:
810 Space2 = PosComment - len(Name)
811 else:
812 Space2 = 1
813
814 return " %s%s%s;%s/* Offset 0x%04X */\n" % (Type, ' ' * Space1, Name, ' ' * Space2, Offset)
815
816
817 def CreateHeaderFile (self, InputHeaderFile, IsInternal):
818 Error = 0
819 FvDir = self._FvDir
820
821 if IsInternal:
822 HeaderFile = os.path.join(FvDir, 'VpdHeader.h')
823 else:
824 HeaderFile = os.path.join(FvDir, 'fsp_vpd.h')
825
826 # Check if header needs to be recreated
827 ReCreate = False
828 if IsInternal:
829 if not os.path.exists(HeaderFile):
830 ReCreate = True
831 else:
832 DscTime = os.path.getmtime(self._DscFile)
833 HeadTime = os.path.getmtime(HeaderFile)
834 if not os.path.exists(InputHeaderFile):
835 InpTime = HeadTime
836 else:
837 InpTime = os.path.getmtime(InputHeaderFile)
838 if DscTime > HeadTime or InpTime > HeadTime:
839 ReCreate = True
840
841 if not ReCreate:
842 self.Error = "No DSC or input header file is changed, skip the header file generating"
843 return 256
844
845 HeaderFd = open(HeaderFile, "w")
846 FileBase = os.path.basename(HeaderFile)
847 FileName = FileBase.replace(".", "_").upper()
848 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
849 HeaderFd.write("#ifndef __%s__\n" % FileName)
850 HeaderFd.write("#define __%s__\n\n" % FileName)
851 HeaderFd.write("#pragma pack(1)\n\n")
852
853 if InputHeaderFile != '':
854 if not os.path.exists(InputHeaderFile):
855 self.Error = "Input header file '%s' does not exist" % InputHeaderFile
856 return 2
857
858 InFd = open(InputHeaderFile, "r")
859 IncLines = InFd.readlines()
860 InFd.close()
861
862 Export = False
863 for Line in IncLines:
864 Match = re.search ("!EXPORT\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line)
865 if Match:
866 if Match.group(1) == "BEGIN":
867 Export = True
868 continue
869 else:
870 Export = False
871 continue
872 if Export:
873 HeaderFd.write(Line)
874 HeaderFd.write("\n\n")
875
876 for Region in ['UPD', 'VPD']:
877
878 # Write PcdVpdRegionSign and PcdImageRevision
879 if Region[0] == 'V':
880 if 'VPD_TOOL_GUID' not in self._MacroDict:
881 self.Error = "VPD_TOOL_GUID definition is missing in DSC file"
882 Error = 1
883 break
884
885 BinFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + ".bin")
886 if not os.path.exists(BinFile):
887 self.Error = "VPD binary file '%s' does not exist" % BinFile
888 Error = 2
889 break
890
891 BinFd = open(BinFile, "rb")
892 IdStr = BinFd.read(0x08)
893 ImageId = struct.unpack('<Q', IdStr)
894 ImageRev = struct.unpack('<I', BinFd.read(0x04))
895 BinFd.close()
896
897 HeaderFd.write("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (ImageId[0], IdStr))
898 HeaderFd.write("#define FSP_IMAGE_REV 0x%08X \n\n" % ImageRev[0])
899
900 HeaderFd.write("typedef struct _" + Region[0] + "PD_DATA_REGION {\n")
901 NextOffset = 0
902 SpaceIdx = 0
903 Offset = 0
904
905 LastVisible = True
906 ResvOffset = 0
907 ResvIdx = 0
908 LineBuffer = []
909 for Item in self._CfgItemList:
910 if Item['region'] != Region:
911 continue
912
913 NextVisible = LastVisible
914 if not IsInternal:
915 if LastVisible and (Item['header'] == 'OFF'):
916 NextVisible = False
917 ResvOffset = Item['offset']
918 elif (not LastVisible) and Item['header'] == 'ON':
919 NextVisible = True
920 Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx
921 ResvIdx = ResvIdx + 1
922 HeaderFd.write(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, ''))
923
924 if Offset < Item["offset"]:
925 if IsInternal or LastVisible:
926 Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx
927 LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, ''))
928 SpaceIdx = SpaceIdx + 1
929 Offset = Item["offset"]
930
931 if Offset != Item["offset"]:
932 print "Unsorted offset 0x%04X\n" % Item["offset"]
933 error = 2
934 break;
935
936 LastVisible = NextVisible
937
938 Offset = Offset + Item["length"]
939 if IsInternal or LastVisible:
940 for Each in LineBuffer:
941 HeaderFd.write (Each)
942 LineBuffer = []
943 HeaderFd.write(self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct']))
944
945 HeaderFd.write("} " + Region[0] + "PD_DATA_REGION;\n\n")
946 HeaderFd.write("#pragma pack()\n\n")
947 HeaderFd.write("#endif\n")
948 HeaderFd.close()
949
950 return Error
951
952 def WriteBsfStruct (self, BsfFd, Item):
953 if Item['type'] == "None":
954 Space = "gPlatformFspPkgTokenSpaceGuid"
955 else:
956 Space = Item['space']
957 Line = " $%s_%s" % (Space, Item['cname'])
958 Match = re.match("\s*\{([x0-9a-fA-F,\s]+)\}\s*", Item['value'])
959 if Match:
960 DefaultValue = Match.group(1).strip()
961 else:
962 DefaultValue = Item['value'].strip()
963 BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue))
964 TmpList = []
965 if Item['type'] == "Combo":
966 if not Item['option'] in self._BuidinOption:
967 OptList = Item['option'].split(',')
968 for Option in OptList:
969 Option = Option.strip()
970 (OpVal, OpStr) = Option.split(':')
971 TmpList.append((OpVal, OpStr))
972 return TmpList
973
974 def WriteBsfOption (self, BsfFd, Item):
975 PcdName = Item['space'] + '_' + Item['cname']
976 WriteHelp = 0
977 if Item['type'] == "Combo":
978 if Item['option'] in self._BuidinOption:
979 Options = self._BuidinOption[Item['option']]
980 else:
981 Options = PcdName
982 BsfFd.write(' %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options));
983 WriteHelp = 1
984 elif Item['type'].startswith("EditNum"):
985 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'])
986 if Match:
987 BsfFd.write(' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1)));
988 WriteHelp = 2
989 elif Item['type'].startswith("EditText"):
990 BsfFd.write(' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name']));
991 WriteHelp = 1
992
993 if WriteHelp > 0:
994 HelpLines = Item['help'].split('\\n\\r')
995 FirstLine = True
996 for HelpLine in HelpLines:
997 if FirstLine:
998 FirstLine = False
999 BsfFd.write(' Help "%s"\n' % (HelpLine));
1000 else:
1001 BsfFd.write(' "%s"\n' % (HelpLine));
1002 if WriteHelp == 2:
1003 BsfFd.write(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3)));
1004
1005 def GenerateBsfFile (self, BsfFile):
1006
1007 if BsfFile == '':
1008 self.Error = "BSF output file '%s' is invalid" % BsfFile
1009 return 1
1010
1011 Error = 0
1012 OptionDict = {}
1013 BsfFd = open(BsfFile, "w")
1014 BsfFd.write("%s\n" % (__copyright_bsf__ % date.today().year))
1015 BsfFd.write("%s\n" % self._GlobalDataDef);
1016 BsfFd.write("StructDef\n")
1017 NextOffset = -1
1018 for Item in self._CfgItemList:
1019 if Item['find'] != '':
1020 BsfFd.write('\n Find "%s"\n' % Item['find'])
1021 NextOffset = Item['offset'] + Item['length']
1022 if Item['name'] != '':
1023 if NextOffset != Item['offset']:
1024 BsfFd.write(" Skip %d bytes\n" % (Item['offset'] - NextOffset))
1025 if len(Item['subreg']) > 0:
1026 NextOffset = Item['offset']
1027 for SubItem in Item['subreg']:
1028 NextOffset += SubItem['length']
1029 if SubItem['name'] == '':
1030 BsfFd.write(" Skip %d bytes\n" % (SubItem['length']))
1031 else:
1032 Options = self.WriteBsfStruct(BsfFd, SubItem)
1033 if len(Options) > 0:
1034 OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options
1035 if (Item['offset'] + Item['length']) < NextOffset:
1036 self.Error = "BSF sub region '%s' length does not match" % (Item['space']+'.'+Item['cname'])
1037 return 2
1038 else:
1039 NextOffset = Item['offset'] + Item['length']
1040 Options = self.WriteBsfStruct(BsfFd, Item)
1041 if len(Options) > 0:
1042 OptionDict[Item['space']+'_'+Item['cname']] = Options
1043 BsfFd.write("\nEndStruct\n\n")
1044
1045 BsfFd.write("%s" % self._BuidinOptionTxt);
1046
1047 for Each in OptionDict:
1048 BsfFd.write("List &%s\n" % Each);
1049 for Item in OptionDict[Each]:
1050 BsfFd.write(' Selection %s , "%s"\n' % (Item[0], Item[1]));
1051 BsfFd.write("EndList\n\n");
1052
1053 BsfFd.write("BeginInfoBlock\n");
1054 BsfFd.write(' PPVer "%s"\n' % (self._CfgBlkDict['ver']));
1055 BsfFd.write(' Description "%s"\n' % (self._CfgBlkDict['name']));
1056 BsfFd.write("EndInfoBlock\n\n");
1057
1058 for Each in self._CfgPageDict:
1059 BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each]);
1060 BsfItems = []
1061 for Item in self._CfgItemList:
1062 if Item['name'] != '':
1063 if Item['page'] != Each:
1064 continue
1065 if len(Item['subreg']) > 0:
1066 for SubItem in Item['subreg']:
1067 if SubItem['name'] != '':
1068 BsfItems.append(SubItem)
1069 else:
1070 BsfItems.append(Item)
1071
1072 BsfItems.sort(key=lambda x: x['order'])
1073
1074 for Item in BsfItems:
1075 self.WriteBsfOption (BsfFd, Item)
1076 BsfFd.write("EndPage\n\n");
1077
1078 BsfFd.close()
1079 return Error
1080
1081
1082 def Usage():
1083 print "GenCfgOpt Version 0.50"
1084 print "Usage:"
1085 print " GenCfgOpt UPDTXT PlatformDscFile BuildFvDir [TxtOutFile] [-D Macros]"
1086 print " GenCfgOpt HEADER PlatformDscFile BuildFvDir [InputHFile] [-D Macros]"
1087 print " GenCfgOpt GENBSF PlatformDscFile BuildFvDir BsfOutFile [-D Macros]"
1088
1089 def Main():
1090 #
1091 # Parse the options and args
1092 #
1093 GenCfgOpt = CGenCfgOpt()
1094 argc = len(sys.argv)
1095 if argc < 4:
1096 Usage()
1097 return 1
1098 else:
1099 DscFile = sys.argv[2]
1100 if not os.path.exists(DscFile):
1101 print "ERROR: Cannot open DSC file '%s' !" % DscFile
1102 return 2
1103
1104 OutFile = ''
1105 if argc > 4:
1106 if sys.argv[4][0] == '-':
1107 Start = 4
1108 else:
1109 OutFile = sys.argv[4]
1110 Start = 5
1111 if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:
1112 print "ERROR: %s !" % GenCfgOpt.Error
1113 return 3
1114
1115 FvDir = sys.argv[3]
1116 if not os.path.isdir(FvDir):
1117 print "ERROR: FV folder '%s' is invalid !" % FvDir
1118 return 4
1119
1120 if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:
1121 print "ERROR: %s !" % GenCfgOpt.Error
1122 return 5
1123
1124 if GenCfgOpt.UpdateVpdSizeField() != 0:
1125 print "ERROR: %s !" % GenCfgOpt.Error
1126 return 6
1127
1128 if GenCfgOpt.UpdateSubRegionDefaultValue() != 0:
1129 print "ERROR: %s !" % GenCfgOpt.Error
1130 return 7
1131
1132 if sys.argv[1] == "UPDTXT":
1133 Ret = GenCfgOpt.CreateUpdTxtFile(OutFile)
1134 if Ret != 0:
1135 # No change is detected
1136 if Ret == 256:
1137 print "INFO: %s !" % (GenCfgOpt.Error)
1138 else :
1139 print "ERROR: %s !" % (GenCfgOpt.Error)
1140 return Ret
1141 elif sys.argv[1] == "HEADER":
1142 Ret = GenCfgOpt.CreateHeaderFile(OutFile, True)
1143 if Ret != 0:
1144 # No change is detected
1145 if Ret == 256:
1146 print "INFO: %s !" % (GenCfgOpt.Error)
1147 else :
1148 print "ERROR: %s !" % (GenCfgOpt.Error)
1149 return Ret
1150 if GenCfgOpt.CreateHeaderFile(OutFile, False) != 0:
1151 print "ERROR: %s !" % GenCfgOpt.Error
1152 return 8
1153 elif sys.argv[1] == "GENBSF":
1154 if GenCfgOpt.GenerateBsfFile(OutFile) != 0:
1155 print "ERROR: %s !" % GenCfgOpt.Error
1156 return 9
1157 else:
1158 if argc < 5:
1159 Usage()
1160 return 1
1161 print "ERROR: Unknown command '%s' !" % sys.argv[1]
1162 Usage()
1163 return 1
1164 return 0
1165 return 0
1166
1167
1168 if __name__ == '__main__':
1169 sys.exit(Main())