]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFspPkg/Tools/GenCfgOpt.py
IntelFspPkg/GenCfgOpt tool add embed structure.
[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', 'EMBED']
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['embed'] = ''
446 ConfigDict['subreg'] = []
447 IsDefSect = False
448 IsVpdSect = True
449 IsUpdSect = False
450 elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower():
451 ConfigDict = {}
452 ConfigDict['header'] = 'ON'
453 ConfigDict['region'] = 'UPD'
454 ConfigDict['order'] = -1
455 ConfigDict['page'] = ''
456 ConfigDict['name'] = ''
457 ConfigDict['find'] = ''
458 ConfigDict['struct'] = ''
459 ConfigDict['embed'] = ''
460 ConfigDict['subreg'] = []
461 IsDefSect = False
462 IsUpdSect = True
463 IsVpdSect = False
464 Found = True
465 else:
466 IsDefSect = False
467 IsUpdSect = False
468 IsVpdSect = False
469 else:
470 if IsDefSect or IsUpdSect or IsVpdSect:
471 if re.match("^!else($|\s+#.+)", DscLine):
472 if IfStack:
473 IfStack[-1] = not IfStack[-1]
474 else:
475 print("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine)
476 raise SystemExit
477 elif re.match("^!endif($|\s+#.+)", DscLine):
478 if IfStack:
479 IfStack.pop()
480 Level = ElifStack.pop()
481 if Level > 0:
482 del IfStack[-Level:]
483 else:
484 print("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine)
485 raise SystemExit
486 else:
487 Result = False
488 Match = re.match("!(ifdef|ifndef)\s+(.+)", DscLine)
489 if Match:
490 Result = self.EvaulateIfdef (Match.group(2))
491 if Match.group(1) == 'ifndef':
492 Result = not Result
493 IfStack.append(Result)
494 ElifStack.append(0)
495 else:
496 Match = re.match("!(if|elseif)\s+(.+)", DscLine)
497 if Match:
498 Result = self.EvaluateExpress(Match.group(2))
499 if Match.group(1) == "if":
500 ElifStack.append(0)
501 IfStack.append(Result)
502 else: #elseif
503 if IfStack:
504 IfStack[-1] = not IfStack[-1]
505 IfStack.append(Result)
506 ElifStack[-1] = ElifStack[-1] + 1
507 else:
508 print("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine)
509 raise SystemExit
510 else:
511 if IfStack:
512 Handle = reduce(lambda x,y: x and y, IfStack)
513 else:
514 Handle = True
515 if Handle:
516 Match = re.match("!include\s+(.+)", DscLine)
517 if Match:
518 IncludeFilePath = Match.group(1)
519 IncludeFilePath = self.ExpandMacros(IncludeFilePath)
520 try:
521 IncludeDsc = open(IncludeFilePath, "r")
522 except:
523 print("ERROR: Cannot open file '%s'" % IncludeFilePath)
524 raise SystemExit
525 NewDscLines = IncludeDsc.readlines()
526 IncludeDsc.close()
527 DscLines = NewDscLines + DscLines
528 else:
529 if DscLine.startswith('!'):
530 print("ERROR: Unrecoginized directive for line '%s'" % DscLine)
531 raise SystemExit
532 if not Handle:
533 continue
534
535 if IsDefSect:
536 #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09
537 Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-.\w]+)", DscLine)
538 if Match:
539 self._MacroDict[Match.group(1)] = Match.group(2)
540 if self.Debug:
541 print "INFO : DEFINE %s = [ %s ]" % (Match.group(1), Match.group(2))
542 else:
543 Match = re.match("^\s*#\s+!(BSF|HDR)\s+(.+)", DscLine)
544 if Match:
545 Remaining = Match.group(2)
546 if Match.group(1) == 'BSF':
547 Match = re.match("(?:^|.+\s+)PAGES:{(.+?)}", Remaining)
548 if Match:
549 # !BSF PAGES:{HSW:"Haswell System Agent", LPT:"Lynx Point PCH"}
550 PageList = Match.group(1).split(',')
551 for Page in PageList:
552 Page = Page.strip()
553 Match = re.match("(\w+):\"(.+)\"", Page)
554 self._CfgPageDict[Match.group(1)] = Match.group(2)
555
556 Match = re.match("(?:^|.+\s+)BLOCK:{NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*}", Remaining)
557 if Match:
558 self._CfgBlkDict['name'] = Match.group(1)
559 self._CfgBlkDict['ver'] = Match.group(2)
560
561 for Key in self._BsfKeyList:
562 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
563 if Match:
564 if Key in ['NAME', 'HELP', 'OPTION'] and Match.group(1).startswith('+'):
565 ConfigDict[Key.lower()] += Match.group(1)[1:]
566 else:
567 ConfigDict[Key.lower()] = Match.group(1)
568 else:
569 for Key in self._HdrKeyList:
570 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
571 if Match:
572 ConfigDict[Key.lower()] = Match.group(1)
573
574 # Check VPD/UPD
575 if IsUpdSect:
576 Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)\s*\|\s*(\d+|0x[0-9a-fA-F]+)\s*\|\s*(.+)",DscLine)
577 else:
578 Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)(?:\s*\|\s*(.+))?", DscLine)
579 if Match:
580 ConfigDict['space'] = Match.group(1)
581 ConfigDict['cname'] = Match.group(2)
582 ConfigDict['offset'] = int (Match.group(3), 16)
583 if ConfigDict['order'] == -1:
584 ConfigDict['order'] = ConfigDict['offset'] << 8
585 else:
586 (Major, Minor) = ConfigDict['order'].split('.')
587 ConfigDict['order'] = (int (Major, 16) << 8 ) + int (Minor, 16)
588 if IsUpdSect:
589 Value = Match.group(5).strip()
590 if Match.group(4).startswith("0x"):
591 Length = int (Match.group(4), 16)
592 else :
593 Length = int (Match.group(4))
594 else:
595 Value = Match.group(4)
596 if Value is None:
597 Value = ''
598 Value = Value.strip()
599 if '|' in Value:
600 Match = re.match("^.+\s*\|\s*(.+)", Value)
601 if Match:
602 Value = Match.group(1)
603 Length = -1
604
605 ConfigDict['length'] = Length
606 Match = re.match("\$\((\w+)\)", Value)
607 if Match:
608 if Match.group(1) in self._MacroDict:
609 Value = self._MacroDict[Match.group(1)]
610
611 ConfigDict['value'] = Value
612 if (len(Value) > 0) and (Value[0] == '{'):
613 Value = self.FormatListValue(ConfigDict)
614
615 if ConfigDict['name'] == '':
616 # Clear BSF specific items
617 ConfigDict['bsfname'] = ''
618 ConfigDict['help'] = ''
619 ConfigDict['type'] = ''
620 ConfigDict['option'] = ''
621
622 self._CfgItemList.append(ConfigDict.copy())
623 ConfigDict['name'] = ''
624 ConfigDict['find'] = ''
625 ConfigDict['struct'] = ''
626 ConfigDict['embed'] = ''
627 ConfigDict['order'] = -1
628 ConfigDict['subreg'] = []
629 else:
630 # It could be a virtual item as below
631 # !BSF FIELD:{1:SerialDebugPortAddress0}
632 Match = re.match("^\s*#\s+!BSF\s+FIELD:{(.+):(\d+)}", DscLine)
633 if Match:
634 SubCfgDict = ConfigDict
635 SubCfgDict['cname'] = Match.group(1)
636 SubCfgDict['length'] = int (Match.group(2))
637 if SubCfgDict['length'] > 0:
638 LastItem = self._CfgItemList[-1]
639 if len(LastItem['subreg']) == 0:
640 SubOffset = 0
641 else:
642 SubOffset += LastItem['subreg'][-1]['length']
643 SubCfgDict['offset'] = SubOffset
644 LastItem['subreg'].append (SubCfgDict.copy())
645 ConfigDict['name'] = ''
646 return Error
647
648 def UpdateSubRegionDefaultValue (self):
649 Error = 0
650 for Item in self._CfgItemList:
651 if len(Item['subreg']) == 0:
652 continue
653 bytearray = []
654 if Item['value'][0] == '{':
655 binlist = Item['value'][1:-1].split(',')
656 for each in binlist:
657 each = each.strip()
658 if each.startswith('0x'):
659 value = int(each, 16)
660 else:
661 value = int(each)
662 bytearray.append(value)
663 else:
664 if Item['value'].startswith('0x'):
665 value = int(Item['value'], 16)
666 else:
667 value = int(Item['value'])
668 idx = 0;
669 while idx < Item['length']:
670 bytearray.append(value & 0xFF)
671 value = value >> 8
672 idx = idx + 1
673 for SubItem in Item['subreg']:
674 if SubItem['length'] in (1,2,4,8):
675 valuelist = [b for b in bytearray[SubItem['offset']:SubItem['offset']+SubItem['length']]]
676 valuelist.reverse()
677 valuestr = "".join('%02X' % b for b in valuelist)
678 SubItem['value'] = '0x%s' % valuestr
679 else:
680 valuestr = ",".join('0x%02X' % b for b in bytearray[SubItem['offset']:SubItem['offset']+SubItem['length']])
681 SubItem['value'] = '{%s}' % valuestr
682 return Error
683
684 def UpdateVpdSizeField (self):
685 FvDir = self._FvDir;
686
687 if 'VPD_TOOL_GUID' not in self._MacroDict:
688 self.Error = "VPD_TOOL_GUID definition is missing in DSC file"
689 return 1
690
691 VpdMapFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + '.map')
692 if not os.path.exists(VpdMapFile):
693 self.Error = "VPD MAP file '%s' does not exist" % VpdMapFile
694 return 2
695
696 MapFd = open(VpdMapFile, "r")
697 MapLines = MapFd.readlines()
698 MapFd.close()
699
700 VpdDict = {}
701 PcdDict = {}
702 for MapLine in MapLines:
703 #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | DEFAULT | 0x0000 | 8 | 0x534450565F425346
704 #gPlatformFspPkgTokenSpaceGuid.PcdVpdRegionSign | 0x0000 | 8 | 0x534450565F425346
705 #gPlatformFspPkgTokenSpaceGuid.PcdTest | 0x0008 | 5 | {0x01,0x02,0x03,0x04,0x05}
706 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)
707 if Match:
708 Space = Match.group(1)
709 Name = Match.group(2)
710 if (self._MapVer == 0) and (Match.group(3) != None):
711 self._MapVer = 1
712 Offset = int (Match.group(4), 16)
713 if Match.group(5).startswith("0x"):
714 Length = int (Match.group(5), 16)
715 else :
716 Length = int (Match.group(5))
717 PcdDict["len"] = Length
718 PcdDict["value"] = Match.group(6)
719 VpdDict[Space+'.'+Name] = dict(PcdDict)
720
721 for Item in self._CfgItemList:
722 if Item['value'] == '':
723 Item['value'] = VpdDict[Item['space']+'.'+Item['cname']]['value']
724 if Item['length'] == -1:
725 Item['length'] = VpdDict[Item['space']+'.'+Item['cname']]['len']
726 if Item['struct'] != '':
727 Type = Item['struct'].strip()
728 if Type.endswith('*') and (Item['length'] != 4):
729 self.Error = "Struct pointer '%s' has invalid size" % Type
730 return 3
731
732 return 0
733
734 def CreateUpdTxtFile (self, UpdTxtFile):
735 FvDir = self._FvDir
736 if 'UPD_TOOL_GUID' not in self._MacroDict:
737 self.Error = "UPD_TOOL_GUID definition is missing in DSC file"
738 return 1
739
740 if UpdTxtFile == '':
741 UpdTxtFile = os.path.join(FvDir, self._MacroDict['UPD_TOOL_GUID'] + '.txt')
742
743 ReCreate = False
744 if not os.path.exists(UpdTxtFile):
745 ReCreate = True
746 else:
747 DscTime = os.path.getmtime(self._DscFile)
748 TxtTime = os.path.getmtime(UpdTxtFile)
749 if DscTime > TxtTime:
750 ReCreate = True
751
752 if not ReCreate:
753 # DSC has not been modified yet
754 # So don't have to re-generate other files
755 self.Error = 'No DSC file change, skip to create UPD TXT file'
756 return 256
757
758 TxtFd = open(UpdTxtFile, "w")
759 TxtFd.write("%s\n" % (__copyright_txt__ % date.today().year))
760
761 NextOffset = 0
762 SpaceIdx = 0
763 if self._MapVer == 1:
764 Default = 'DEFAULT|'
765 else:
766 Default = ''
767 for Item in self._CfgItemList:
768 if Item['region'] != 'UPD':
769 continue
770 Offset = Item['offset']
771 if NextOffset < Offset:
772 # insert one line
773 TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset, Offset - NextOffset))
774 SpaceIdx = SpaceIdx + 1
775 NextOffset = Offset + Item['length']
776 TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'],Item['length'],Item['value']))
777 TxtFd.close()
778 return 0
779
780 def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help):
781 PosName = 28
782 PosComment = 30
783 NameLine=''
784 HelpLine=''
785
786 IsArray = False
787 if Length in [1,2,4,8]:
788 Type = "UINT%d" % (Length * 8)
789 else:
790 IsArray = True
791 Type = "UINT8"
792
793 if Item and Item['value'].startswith('{'):
794 Type = "UINT8"
795 IsArray = True
796
797 if Struct != '':
798 Type = Struct
799 if Struct in ['UINT8','UINT16','UINT32','UINT64']:
800 IsArray = True
801 Unit = int(Type[4:]) / 8
802 Length = Length / Unit
803 else:
804 IsArray = False
805
806 if IsArray:
807 Name = Name + '[%d]' % Length
808
809 if len(Type) < PosName:
810 Space1 = PosName - len(Type)
811 else:
812 Space1 = 1
813
814 if BsfName != '':
815 NameLine=" %s\n" % BsfName
816
817 if Help != '':
818 HelpLine=" %s\n" % Help
819
820 if Offset is None:
821 OffsetStr = '????'
822 else:
823 OffsetStr = '0x%04X' % Offset
824
825 return "/** Offset %s\n%s%s**/\n %s%s%s;\n" % (OffsetStr, NameLine, HelpLine, Type, ' ' * Space1, Name,)
826
827 def PostProcessBody (self, TextBody):
828 NewTextBody = []
829 OldTextBody = []
830 IncludeLine = False
831 StructName = ''
832 VariableName = ''
833 for Line in TextBody:
834 Match = re.match("^/\*\sEMBED_STRUCT:(\w+):(\w+):(START|END)\s\*/\s([\s\S]*)", Line)
835 if Match:
836 Line = Match.group(4)
837
838 if Match and Match.group(3) == 'START':
839 NewTextBody.append ('typedef struct {\n')
840 StructName = Match.group(1)
841 VariableName = Match.group(2)
842 MatchOffset = re.search('/\*\*\sOffset\s0x([a-fA-F0-9]+)', Line)
843 if MatchOffset:
844 Offset = int(MatchOffset.group(1), 16)
845 else:
846 Offset = None
847 Line
848 IncludeLine = True
849 OldTextBody.append (self.CreateField (None, VariableName, 0, Offset, StructName, '', ''))
850 if IncludeLine:
851 NewTextBody.append (Line)
852 else:
853 OldTextBody.append (Line)
854
855 if Match and Match.group(3) == 'END':
856 if (StructName != Match.group(1)) or (VariableName != Match.group(2)):
857 print "Unmatched struct name '%s' and '%s' !" % (StructName, Match.group(1))
858 else:
859 NewTextBody.append ('} %s;\n\n' % StructName)
860 IncludeLine = False
861 NewTextBody.extend(OldTextBody)
862 return NewTextBody
863
864 def CreateHeaderFile (self, InputHeaderFile, IsInternal):
865 FvDir = self._FvDir
866
867 if IsInternal:
868 HeaderFile = os.path.join(FvDir, 'FspUpdVpdInternal.h')
869 else:
870 HeaderFile = os.path.join(FvDir, 'FspUpdVpd.h')
871
872 # Check if header needs to be recreated
873 ReCreate = False
874 if IsInternal:
875 if not os.path.exists(HeaderFile):
876 ReCreate = True
877 else:
878 DscTime = os.path.getmtime(self._DscFile)
879 HeadTime = os.path.getmtime(HeaderFile)
880 if not os.path.exists(InputHeaderFile):
881 InpTime = HeadTime
882 else:
883 InpTime = os.path.getmtime(InputHeaderFile)
884 if DscTime > HeadTime or InpTime > HeadTime:
885 ReCreate = True
886
887 if not ReCreate:
888 self.Error = "No DSC or input header file is changed, skip the header file generating"
889 return 256
890
891 TxtBody = []
892 for Region in ['UPD', 'VPD']:
893
894 # Write PcdVpdRegionSign and PcdImageRevision
895 if Region[0] == 'V':
896 if 'VPD_TOOL_GUID' not in self._MacroDict:
897 self.Error = "VPD_TOOL_GUID definition is missing in DSC file"
898 return 1
899
900 BinFile = os.path.join(FvDir, self._MacroDict['VPD_TOOL_GUID'] + ".bin")
901 if not os.path.exists(BinFile):
902 self.Error = "VPD binary file '%s' does not exist" % BinFile
903 return 2
904
905 BinFd = open(BinFile, "rb")
906 IdStr = BinFd.read(0x08)
907 ImageId = struct.unpack('<Q', IdStr)
908 ImageRev = struct.unpack('<I', BinFd.read(0x04))
909 BinFd.close()
910
911 TxtBody.append("#define FSP_IMAGE_ID 0x%016X /* '%s' */\n" % (ImageId[0], IdStr))
912 TxtBody.append("#define FSP_IMAGE_REV 0x%08X \n\n" % ImageRev[0])
913
914 TxtBody.append("typedef struct _" + Region[0] + "PD_DATA_REGION {\n")
915 NextOffset = 0
916 SpaceIdx = 0
917 Offset = 0
918
919 LastVisible = True
920 ResvOffset = 0
921 ResvIdx = 0
922 LineBuffer = []
923 for Item in self._CfgItemList:
924 if Item['region'] != Region:
925 continue
926
927 NextVisible = LastVisible
928 if not IsInternal:
929 if LastVisible and (Item['header'] == 'OFF'):
930 NextVisible = False
931 ResvOffset = Item['offset']
932 elif (not LastVisible) and Item['header'] == 'ON':
933 NextVisible = True
934 Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx
935 ResvIdx = ResvIdx + 1
936 TxtBody.append(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, '', '', ''))
937
938 if Offset < Item["offset"]:
939 if IsInternal or LastVisible:
940 Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx
941 LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, '', '', ''))
942 SpaceIdx = SpaceIdx + 1
943 Offset = Item["offset"]
944
945 if Offset != Item["offset"]:
946 self.Error = "Unsorted offset 0x%04X\n" % Item["offset"]
947 return 3
948
949 LastVisible = NextVisible
950
951 Offset = Offset + Item["length"]
952 if IsInternal or LastVisible:
953 for Each in LineBuffer:
954 TxtBody.append (Each)
955 LineBuffer = []
956 Embed = Item["embed"].upper()
957 if Embed.endswith(':START') or Embed.endswith(':END'):
958 Marker = '/* EMBED_STRUCT:%s */ ' % Item["embed"]
959 else:
960 if Embed == '':
961 Marker = '';
962 else:
963 self.Error = "Invalid embedded structure format '%s'!\n" % Item["embed"]
964 return 4
965 Line = Marker + self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct'], Item['name'], Item['help'])
966 TxtBody.append(Line)
967
968 TxtBody.append("} " + Region[0] + "PD_DATA_REGION;\n\n")
969
970 # Handle the embedded data structure
971 TxtBody = self.PostProcessBody (TxtBody)
972
973 HeaderFd = open(HeaderFile, "w")
974 FileBase = os.path.basename(HeaderFile)
975 FileName = FileBase.replace(".", "_").upper()
976 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
977 HeaderFd.write("#ifndef __%s__\n" % FileName)
978 HeaderFd.write("#define __%s__\n\n" % FileName)
979 HeaderFd.write("#pragma pack(1)\n\n")
980
981 if InputHeaderFile != '':
982 if not os.path.exists(InputHeaderFile):
983 self.Error = "Input header file '%s' does not exist" % InputHeaderFile
984 return 6
985
986 InFd = open(InputHeaderFile, "r")
987 IncLines = InFd.readlines()
988 InFd.close()
989
990 Export = False
991 for Line in IncLines:
992 Match = re.search ("!EXPORT\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line)
993 if Match:
994 if Match.group(1) == "BEGIN":
995 Export = True
996 continue
997 else:
998 Export = False
999 continue
1000 if Export:
1001 HeaderFd.write(Line)
1002 HeaderFd.write("\n\n")
1003
1004 for Line in TxtBody:
1005 HeaderFd.write (Line)
1006 HeaderFd.write("#pragma pack()\n\n")
1007 HeaderFd.write("#endif\n")
1008 HeaderFd.close()
1009
1010 return 0
1011
1012 def WriteBsfStruct (self, BsfFd, Item):
1013 if Item['type'] == "None":
1014 Space = "gPlatformFspPkgTokenSpaceGuid"
1015 else:
1016 Space = Item['space']
1017 Line = " $%s_%s" % (Space, Item['cname'])
1018 Match = re.match("\s*\{([x0-9a-fA-F,\s]+)\}\s*", Item['value'])
1019 if Match:
1020 DefaultValue = Match.group(1).strip()
1021 else:
1022 DefaultValue = Item['value'].strip()
1023 BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue))
1024 TmpList = []
1025 if Item['type'] == "Combo":
1026 if not Item['option'] in self._BuidinOption:
1027 OptList = Item['option'].split(',')
1028 for Option in OptList:
1029 Option = Option.strip()
1030 (OpVal, OpStr) = Option.split(':')
1031 TmpList.append((OpVal, OpStr))
1032 return TmpList
1033
1034 def WriteBsfOption (self, BsfFd, Item):
1035 PcdName = Item['space'] + '_' + Item['cname']
1036 WriteHelp = 0
1037 if Item['type'] == "Combo":
1038 if Item['option'] in self._BuidinOption:
1039 Options = self._BuidinOption[Item['option']]
1040 else:
1041 Options = PcdName
1042 BsfFd.write(' %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options));
1043 WriteHelp = 1
1044 elif Item['type'].startswith("EditNum"):
1045 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'])
1046 if Match:
1047 BsfFd.write(' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1)));
1048 WriteHelp = 2
1049 elif Item['type'].startswith("EditText"):
1050 BsfFd.write(' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name']));
1051 WriteHelp = 1
1052 elif Item['type'] == "Table":
1053 Columns = Item['option'].split(',')
1054 if len(Columns) != 0:
1055 BsfFd.write(' %s $%s "%s",' % (Item['type'], PcdName, Item['name']));
1056 for Col in Columns:
1057 Fmt = Col.split(':')
1058 if len(Fmt) != 3:
1059 raise Exception("Column format '%s' is invalid !" % Fmt)
1060 try:
1061 Dtype = int(Fmt[1].strip())
1062 except:
1063 raise Exception("Column size '%s' is invalid !" % Fmt[1])
1064 BsfFd.write('\n Column "%s", %d bytes, %s' % (Fmt[0].strip(), Dtype, Fmt[2].strip()))
1065 BsfFd.write(',\n')
1066 WriteHelp = 1
1067
1068 if WriteHelp > 0:
1069 HelpLines = Item['help'].split('\\n\\r')
1070 FirstLine = True
1071 for HelpLine in HelpLines:
1072 if FirstLine:
1073 FirstLine = False
1074 BsfFd.write(' Help "%s"\n' % (HelpLine));
1075 else:
1076 BsfFd.write(' "%s"\n' % (HelpLine));
1077 if WriteHelp == 2:
1078 BsfFd.write(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3)));
1079
1080 def GenerateBsfFile (self, BsfFile):
1081
1082 if BsfFile == '':
1083 self.Error = "BSF output file '%s' is invalid" % BsfFile
1084 return 1
1085
1086 Error = 0
1087 OptionDict = {}
1088 BsfFd = open(BsfFile, "w")
1089 BsfFd.write("%s\n" % (__copyright_bsf__ % date.today().year))
1090 BsfFd.write("%s\n" % self._GlobalDataDef);
1091 BsfFd.write("StructDef\n")
1092 NextOffset = -1
1093 for Item in self._CfgItemList:
1094 if Item['find'] != '':
1095 BsfFd.write('\n Find "%s"\n' % Item['find'])
1096 NextOffset = Item['offset'] + Item['length']
1097 if Item['name'] != '':
1098 if NextOffset != Item['offset']:
1099 BsfFd.write(" Skip %d bytes\n" % (Item['offset'] - NextOffset))
1100 if len(Item['subreg']) > 0:
1101 NextOffset = Item['offset']
1102 for SubItem in Item['subreg']:
1103 NextOffset += SubItem['length']
1104 if SubItem['name'] == '':
1105 BsfFd.write(" Skip %d bytes\n" % (SubItem['length']))
1106 else:
1107 Options = self.WriteBsfStruct(BsfFd, SubItem)
1108 if len(Options) > 0:
1109 OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options
1110 if (Item['offset'] + Item['length']) < NextOffset:
1111 self.Error = "BSF sub region '%s' length does not match" % (Item['space']+'.'+Item['cname'])
1112 return 2
1113 else:
1114 NextOffset = Item['offset'] + Item['length']
1115 Options = self.WriteBsfStruct(BsfFd, Item)
1116 if len(Options) > 0:
1117 OptionDict[Item['space']+'_'+Item['cname']] = Options
1118 BsfFd.write("\nEndStruct\n\n")
1119
1120 BsfFd.write("%s" % self._BuidinOptionTxt);
1121
1122 for Each in OptionDict:
1123 BsfFd.write("List &%s\n" % Each);
1124 for Item in OptionDict[Each]:
1125 BsfFd.write(' Selection %s , "%s"\n' % (Item[0], Item[1]));
1126 BsfFd.write("EndList\n\n");
1127
1128 BsfFd.write("BeginInfoBlock\n");
1129 BsfFd.write(' PPVer "%s"\n' % (self._CfgBlkDict['ver']));
1130 BsfFd.write(' Description "%s"\n' % (self._CfgBlkDict['name']));
1131 BsfFd.write("EndInfoBlock\n\n");
1132
1133 for Each in self._CfgPageDict:
1134 BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each]);
1135 BsfItems = []
1136 for Item in self._CfgItemList:
1137 if Item['name'] != '':
1138 if Item['page'] != Each:
1139 continue
1140 if len(Item['subreg']) > 0:
1141 for SubItem in Item['subreg']:
1142 if SubItem['name'] != '':
1143 BsfItems.append(SubItem)
1144 else:
1145 BsfItems.append(Item)
1146
1147 BsfItems.sort(key=lambda x: x['order'])
1148
1149 for Item in BsfItems:
1150 self.WriteBsfOption (BsfFd, Item)
1151 BsfFd.write("EndPage\n\n");
1152
1153 BsfFd.close()
1154 return Error
1155
1156
1157 def Usage():
1158 print "GenCfgOpt Version 0.50"
1159 print "Usage:"
1160 print " GenCfgOpt UPDTXT PlatformDscFile BuildFvDir [TxtOutFile] [-D Macros]"
1161 print " GenCfgOpt HEADER PlatformDscFile BuildFvDir [InputHFile] [-D Macros]"
1162 print " GenCfgOpt GENBSF PlatformDscFile BuildFvDir BsfOutFile [-D Macros]"
1163
1164 def Main():
1165 #
1166 # Parse the options and args
1167 #
1168 GenCfgOpt = CGenCfgOpt()
1169 argc = len(sys.argv)
1170 if argc < 4:
1171 Usage()
1172 return 1
1173 else:
1174 DscFile = sys.argv[2]
1175 if not os.path.exists(DscFile):
1176 print "ERROR: Cannot open DSC file '%s' !" % DscFile
1177 return 2
1178
1179 OutFile = ''
1180 if argc > 4:
1181 if sys.argv[4][0] == '-':
1182 Start = 4
1183 else:
1184 OutFile = sys.argv[4]
1185 Start = 5
1186 if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:
1187 print "ERROR: Macro parsing failed !"
1188 return 3
1189
1190 FvDir = sys.argv[3]
1191 if not os.path.isdir(FvDir):
1192 print "ERROR: FV folder '%s' is invalid !" % FvDir
1193 return 4
1194
1195 if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:
1196 print "ERROR: %s !" % GenCfgOpt.Error
1197 return 5
1198
1199 if GenCfgOpt.UpdateVpdSizeField() != 0:
1200 print "ERROR: %s !" % GenCfgOpt.Error
1201 return 6
1202
1203 if GenCfgOpt.UpdateSubRegionDefaultValue() != 0:
1204 print "ERROR: %s !" % GenCfgOpt.Error
1205 return 7
1206
1207 if sys.argv[1] == "UPDTXT":
1208 Ret = GenCfgOpt.CreateUpdTxtFile(OutFile)
1209 if Ret != 0:
1210 # No change is detected
1211 if Ret == 256:
1212 print "INFO: %s !" % (GenCfgOpt.Error)
1213 else :
1214 print "ERROR: %s !" % (GenCfgOpt.Error)
1215 return Ret
1216 elif sys.argv[1] == "HEADER":
1217 Ret = GenCfgOpt.CreateHeaderFile(OutFile, True)
1218 if Ret != 0:
1219 # No change is detected
1220 if Ret == 256:
1221 print "INFO: %s !" % (GenCfgOpt.Error)
1222 else :
1223 print "ERROR: %s !" % (GenCfgOpt.Error)
1224 return Ret
1225 if GenCfgOpt.CreateHeaderFile(OutFile, False) != 0:
1226 print "ERROR: %s !" % GenCfgOpt.Error
1227 return 8
1228 elif sys.argv[1] == "GENBSF":
1229 if GenCfgOpt.GenerateBsfFile(OutFile) != 0:
1230 print "ERROR: %s !" % GenCfgOpt.Error
1231 return 9
1232 else:
1233 if argc < 5:
1234 Usage()
1235 return 1
1236 print "ERROR: Unknown command '%s' !" % sys.argv[1]
1237 Usage()
1238 return 1
1239 return 0
1240 return 0
1241
1242
1243 if __name__ == '__main__':
1244 sys.exit(Main())