]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/GenCfgOpt.py
IntelFsp2Pkg/GenCfgOpt.py: Support PCD input from command line
[mirror_edk2.git] / IntelFsp2Pkg / Tools / GenCfgOpt.py
1 ## @ GenCfgOpt.py
2 #
3 # Copyright (c) 2014 - 2018, 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 BuildOptionPcd = []
92
93 class CLogicalExpression:
94 def __init__(self):
95 self.index = 0
96 self.string = ''
97
98 def errExit(self, err = ''):
99 print "ERROR: Express parsing for:"
100 print " %s" % self.string
101 print " %s^" % (' ' * self.index)
102 if err:
103 print "INFO : %s" % err
104 raise SystemExit
105
106 def getNonNumber (self, n1, n2):
107 if not n1.isdigit():
108 return n1
109 if not n2.isdigit():
110 return n2
111 return None
112
113 def getCurr(self, lens = 1):
114 try:
115 if lens == -1:
116 return self.string[self.index :]
117 else:
118 if self.index + lens > len(self.string):
119 lens = len(self.string) - self.index
120 return self.string[self.index : self.index + lens]
121 except Exception:
122 return ''
123
124 def isLast(self):
125 return self.index == len(self.string)
126
127 def moveNext(self, len = 1):
128 self.index += len
129
130 def skipSpace(self):
131 while not self.isLast():
132 if self.getCurr() in ' \t':
133 self.moveNext()
134 else:
135 return
136
137 def normNumber (self, val):
138 return True if val else False
139
140 def getNumber(self, var):
141 var = var.strip()
142 if re.match('^0x[a-fA-F0-9]+$', var):
143 value = int(var, 16)
144 elif re.match('^[+-]?\d+$', var):
145 value = int(var, 10)
146 else:
147 value = None
148 return value
149
150 def parseValue(self):
151 self.skipSpace()
152 var = ''
153 while not self.isLast():
154 char = self.getCurr()
155 if re.match('^[\w.]', char):
156 var += char
157 self.moveNext()
158 else:
159 break
160 val = self.getNumber(var)
161 if val is None:
162 value = var
163 else:
164 value = "%d" % val
165 return value
166
167 def parseSingleOp(self):
168 self.skipSpace()
169 if re.match('^NOT\W', self.getCurr(-1)):
170 self.moveNext(3)
171 op = self.parseBrace()
172 val = self.getNumber (op)
173 if val is None:
174 self.errExit ("'%s' is not a number" % op)
175 return "%d" % (not self.normNumber(int(op)))
176 else:
177 return self.parseValue()
178
179 def parseBrace(self):
180 self.skipSpace()
181 char = self.getCurr()
182 if char == '(':
183 self.moveNext()
184 value = self.parseExpr()
185 self.skipSpace()
186 if self.getCurr() != ')':
187 self.errExit ("Expecting closing brace or operator")
188 self.moveNext()
189 return value
190 else:
191 value = self.parseSingleOp()
192 return value
193
194 def parseCompare(self):
195 value = self.parseBrace()
196 while True:
197 self.skipSpace()
198 char = self.getCurr()
199 if char in ['<', '>']:
200 self.moveNext()
201 next = self.getCurr()
202 if next == '=':
203 op = char + next
204 self.moveNext()
205 else:
206 op = char
207 result = self.parseBrace()
208 test = self.getNonNumber(result, value)
209 if test is None:
210 value = "%d" % self.normNumber(eval (value + op + result))
211 else:
212 self.errExit ("'%s' is not a valid number for comparision" % test)
213 elif char in ['=', '!']:
214 op = self.getCurr(2)
215 if op in ['==', '!=']:
216 self.moveNext(2)
217 result = self.parseBrace()
218 test = self.getNonNumber(result, value)
219 if test is None:
220 value = "%d" % self.normNumber((eval (value + op + result)))
221 else:
222 value = "%d" % self.normNumber(eval ("'" + value + "'" + op + "'" + result + "'"))
223 else:
224 break
225 else:
226 break
227 return value
228
229 def parseAnd(self):
230 value = self.parseCompare()
231 while True:
232 self.skipSpace()
233 if re.match('^AND\W', self.getCurr(-1)):
234 self.moveNext(3)
235 result = self.parseCompare()
236 test = self.getNonNumber(result, value)
237 if test is None:
238 value = "%d" % self.normNumber(int(value) & int(result))
239 else:
240 self.errExit ("'%s' is not a valid op number for AND" % test)
241 else:
242 break
243 return value
244
245 def parseOrXor(self):
246 value = self.parseAnd()
247 op = None
248 while True:
249 self.skipSpace()
250 op = None
251 if re.match('^XOR\W', self.getCurr(-1)):
252 self.moveNext(3)
253 op = '^'
254 elif re.match('^OR\W', self.getCurr(-1)):
255 self.moveNext(2)
256 op = '|'
257 else:
258 break
259 if op:
260 result = self.parseAnd()
261 test = self.getNonNumber(result, value)
262 if test is None:
263 value = "%d" % self.normNumber(eval (value + op + result))
264 else:
265 self.errExit ("'%s' is not a valid op number for XOR/OR" % test)
266 return value
267
268 def parseExpr(self):
269 return self.parseOrXor()
270
271 def getResult(self):
272 value = self.parseExpr()
273 self.skipSpace()
274 if not self.isLast():
275 self.errExit ("Unexpected character found '%s'" % self.getCurr())
276 test = self.getNumber(value)
277 if test is None:
278 self.errExit ("Result '%s' is not a number" % value)
279 return int(value)
280
281 def evaluateExpress (self, Expr):
282 self.index = 0
283 self.string = Expr
284 if self.getResult():
285 Result = True
286 else:
287 Result = False
288 return Result
289
290 class CGenCfgOpt:
291 def __init__(self):
292 self.Debug = False
293 self.Error = ''
294
295 self._GlobalDataDef = """
296 GlobalDataDef
297 SKUID = 0, "DEFAULT"
298 EndGlobalData
299
300 """
301 self._BuidinOptionTxt = """
302 List &EN_DIS
303 Selection 0x1 , "Enabled"
304 Selection 0x0 , "Disabled"
305 EndList
306
307 """
308
309 self._BsfKeyList = ['FIND','NAME','HELP','TYPE','PAGE','OPTION','ORDER']
310 self._HdrKeyList = ['HEADER','STRUCT', 'EMBED', 'COMMENT']
311 self._BuidinOption = {'$EN_DIS' : 'EN_DIS'}
312
313 self._MacroDict = {}
314 self._PcdsDict = {}
315 self._CfgBlkDict = {}
316 self._CfgPageDict = {}
317 self._CfgItemList = []
318 self._DscFile = ''
319 self._FvDir = ''
320 self._MapVer = 0
321
322 def ParseMacros (self, MacroDefStr):
323 # ['-DABC=1', '-D', 'CFG_DEBUG=1', '-D', 'CFG_OUTDIR=Build']
324 self._MacroDict = {}
325 IsExpression = False
326 for Macro in MacroDefStr:
327 if Macro.startswith('-D'):
328 IsExpression = True
329 if len(Macro) > 2:
330 Macro = Macro[2:]
331 else :
332 continue
333 if IsExpression:
334 IsExpression = False
335 Match = re.match("(\w+)=(.+)", Macro)
336 if Match:
337 self._MacroDict[Match.group(1)] = Match.group(2)
338 else:
339 Match = re.match("(\w+)", Macro)
340 if Match:
341 self._MacroDict[Match.group(1)] = ''
342 if len(self._MacroDict) == 0:
343 Error = 1
344 else:
345 Error = 0
346 if self.Debug:
347 print "INFO : Macro dictionary:"
348 for Each in self._MacroDict:
349 print " $(%s) = [ %s ]" % (Each , self._MacroDict[Each])
350 return Error
351
352 def EvaulateIfdef (self, Macro):
353 Result = Macro in self._MacroDict
354 if self.Debug:
355 print "INFO : Eval Ifdef [%s] : %s" % (Macro, Result)
356 return Result
357
358 def ExpandMacros (self, Input):
359 Line = Input
360 Match = re.findall("\$\(\w+\)", Input)
361 if Match:
362 for Each in Match:
363 Variable = Each[2:-1]
364 if Variable in self._MacroDict:
365 Line = Line.replace(Each, self._MacroDict[Variable])
366 else:
367 if self.Debug:
368 print "WARN : %s is not defined" % Each
369 Line = Line.replace(Each, Each[2:-1])
370 return Line
371
372 def ExpandPcds (self, Input):
373 Line = Input
374 Match = re.findall("(\w+\.\w+)", Input)
375 if Match:
376 for PcdName in Match:
377 if PcdName in self._PcdsDict:
378 Line = Line.replace(PcdName, self._PcdsDict[PcdName])
379 else:
380 if self.Debug:
381 print "WARN : %s is not defined" % PcdName
382 return Line
383
384 def EvaluateExpress (self, Expr):
385 ExpExpr = self.ExpandPcds(Expr)
386 ExpExpr = self.ExpandMacros(ExpExpr)
387 LogExpr = CLogicalExpression()
388 Result = LogExpr.evaluateExpress (ExpExpr)
389 if self.Debug:
390 print "INFO : Eval Express [%s] : %s" % (Expr, Result)
391 return Result
392
393 def FormatListValue(self, ConfigDict):
394 Struct = ConfigDict['struct']
395 if Struct not in ['UINT8','UINT16','UINT32','UINT64']:
396 return
397
398 dataarray = []
399 binlist = ConfigDict['value'][1:-1].split(',')
400 for each in binlist:
401 each = each.strip()
402 if each.startswith('0x'):
403 value = int(each, 16)
404 else:
405 value = int(each)
406 dataarray.append(value)
407
408 unit = int(Struct[4:]) / 8
409 if int(ConfigDict['length']) != unit * len(dataarray):
410 raise Exception("Array size is not proper for '%s' !" % ConfigDict['cname'])
411
412 bytearray = []
413 for each in dataarray:
414 value = each
415 for loop in xrange(unit):
416 bytearray.append("0x%02X" % (value & 0xFF))
417 value = value >> 8
418 newvalue = '{' + ','.join(bytearray) + '}'
419 ConfigDict['value'] = newvalue
420 return ""
421
422 def ParseDscFile (self, DscFile, FvDir):
423 Hardcode = False
424 AutoAlign = False
425 self._CfgItemList = []
426 self._CfgPageDict = {}
427 self._CfgBlkDict = {}
428 self._DscFile = DscFile
429 self._FvDir = FvDir
430
431 IsDefSect = False
432 IsPcdSect = False
433 IsUpdSect = False
434 IsVpdSect = False
435
436 IfStack = []
437 ElifStack = []
438 Error = 0
439 ConfigDict = {}
440
441 DscFd = open(DscFile, "r")
442 DscLines = DscFd.readlines()
443 DscFd.close()
444
445 MaxAlign = 32 #Default align to 32, but if there are 64 bit unit, align to 64
446 SizeAlign = 0 #record the struct max align
447 while len(DscLines):
448 DscLine = DscLines.pop(0).strip()
449 Handle = False
450 Match = re.match("^\[(.+)\]", DscLine)
451 if Match is not None:
452 IsDefSect = False
453 IsPcdSect = False
454 IsVpdSect = False
455 IsUpdSect = False
456 if Match.group(1).lower() == "Defines".lower():
457 IsDefSect = True
458 if (Match.group(1).lower() == "PcdsFeatureFlag".lower() or Match.group(1).lower() == "PcdsFixedAtBuild".lower()):
459 IsPcdSect = True
460 elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower():
461 ConfigDict = {}
462 ConfigDict['header'] = 'ON'
463 ConfigDict['region'] = 'UPD'
464 ConfigDict['order'] = -1
465 ConfigDict['page'] = ''
466 ConfigDict['name'] = ''
467 ConfigDict['find'] = ''
468 ConfigDict['struct'] = ''
469 ConfigDict['embed'] = ''
470 ConfigDict['comment'] = ''
471 ConfigDict['subreg'] = []
472 IsUpdSect = True
473 Offset = 0
474 else:
475 if IsDefSect or IsPcdSect or IsUpdSect or IsVpdSect:
476 if re.match("^!else($|\s+#.+)", DscLine):
477 if IfStack:
478 IfStack[-1] = not IfStack[-1]
479 else:
480 print("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine)
481 raise SystemExit
482 elif re.match("^!endif($|\s+#.+)", DscLine):
483 if IfStack:
484 IfStack.pop()
485 Level = ElifStack.pop()
486 if Level > 0:
487 del IfStack[-Level:]
488 else:
489 print("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine)
490 raise SystemExit
491 else:
492 Result = False
493 Match = re.match("!(ifdef|ifndef)\s+(.+)", DscLine)
494 if Match:
495 Result = self.EvaulateIfdef (Match.group(2))
496 if Match.group(1) == 'ifndef':
497 Result = not Result
498 IfStack.append(Result)
499 ElifStack.append(0)
500 else:
501 Match = re.match("!(if|elseif)\s+(.+)", DscLine.split("#")[0])
502 if Match:
503 Result = self.EvaluateExpress(Match.group(2))
504 if Match.group(1) == "if":
505 ElifStack.append(0)
506 IfStack.append(Result)
507 else: #elseif
508 if IfStack:
509 IfStack[-1] = not IfStack[-1]
510 IfStack.append(Result)
511 ElifStack[-1] = ElifStack[-1] + 1
512 else:
513 print("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine)
514 raise SystemExit
515 else:
516 if IfStack:
517 Handle = reduce(lambda x,y: x and y, IfStack)
518 else:
519 Handle = True
520 if Handle:
521 Match = re.match("!include\s+(.+)", DscLine)
522 if Match:
523 IncludeFilePath = Match.group(1)
524 IncludeFilePath = self.ExpandMacros(IncludeFilePath)
525 PackagesPath = os.getenv("PACKAGES_PATH")
526 if PackagesPath:
527 for PackagePath in PackagesPath.split(os.pathsep):
528 IncludeFilePathAbs = os.path.join(os.path.normpath(PackagePath), os.path.normpath(IncludeFilePath))
529 if os.path.exists(IncludeFilePathAbs):
530 IncludeDsc = open(IncludeFilePathAbs, "r")
531 break
532 else:
533 IncludeDsc = open(IncludeFilePath, "r")
534 if IncludeDsc == None:
535 print("ERROR: Cannot open file '%s'" % IncludeFilePath)
536 raise SystemExit
537 NewDscLines = IncludeDsc.readlines()
538 IncludeDsc.close()
539 DscLines = NewDscLines + DscLines
540 Offset = 0
541 else:
542 if DscLine.startswith('!'):
543 print("ERROR: Unrecoginized directive for line '%s'" % DscLine)
544 raise SystemExit
545 if not Handle:
546 continue
547
548 if IsDefSect:
549 #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09
550 #DEFINE FSP_T_UPD_TOOL_GUID = 34686CA3-34F9-4901-B82A-BA630F0714C6
551 #DEFINE FSP_M_UPD_TOOL_GUID = 39A250DB-E465-4DD1-A2AC-E2BD3C0E2385
552 #DEFINE FSP_S_UPD_TOOL_GUID = CAE3605B-5B34-4C85-B3D7-27D54273C40F
553 Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([-.\w]+)", DscLine)
554 if Match:
555 self._MacroDict[Match.group(1)] = Match.group(2)
556 if self.Debug:
557 print "INFO : DEFINE %s = [ %s ]" % (Match.group(1), Match.group(2))
558 elif IsPcdSect:
559 #gSiPkgTokenSpaceGuid.PcdTxtEnable|FALSE
560 #gSiPkgTokenSpaceGuid.PcdOverclockEnable|TRUE
561 Match = re.match("^\s*([\w\.]+)\s*\|\s*(\w+)", DscLine)
562 if Match:
563 self._PcdsDict[Match.group(1)] = Match.group(2)
564 if self.Debug:
565 print "INFO : PCD %s = [ %s ]" % (Match.group(1), Match.group(2))
566 i = 0
567 while i < len(BuildOptionPcd):
568 Match = re.match("\s*([\w\.]+)\s*\=\s*(\w+)", BuildOptionPcd[i])
569 if Match:
570 self._PcdsDict[Match.group(1)] = Match.group(2)
571 i += 1
572 else:
573 Match = re.match("^\s*#\s+(!BSF|@Bsf|!HDR)\s+(.+)", DscLine)
574 if Match:
575 Remaining = Match.group(2)
576 if Match.group(1) == '!BSF' or Match.group(1) == '@Bsf':
577 Match = re.match("(?:^|.+\s+)PAGES:{(.+?)}", Remaining)
578 if Match:
579 # !BSF PAGES:{HSW:"Haswell System Agent", LPT:"Lynx Point PCH"}
580 PageList = Match.group(1).split(',')
581 for Page in PageList:
582 Page = Page.strip()
583 Match = re.match("(\w+):\"(.+)\"", Page)
584 self._CfgPageDict[Match.group(1)] = Match.group(2)
585
586 Match = re.match("(?:^|.+\s+)BLOCK:{NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*}", Remaining)
587 if Match:
588 self._CfgBlkDict['name'] = Match.group(1)
589 self._CfgBlkDict['ver'] = Match.group(2)
590
591 for Key in self._BsfKeyList:
592 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
593 if Match:
594 if Key in ['NAME', 'HELP', 'OPTION'] and Match.group(1).startswith('+'):
595 ConfigDict[Key.lower()] += Match.group(1)[1:]
596 else:
597 ConfigDict[Key.lower()] = Match.group(1)
598 else:
599 for Key in self._HdrKeyList:
600 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
601 if Match:
602 ConfigDict[Key.lower()] = Match.group(1)
603
604 Match = re.match("^\s*#\s+@Prompt\s+(.+)", DscLine)
605 if Match:
606 ConfigDict['name'] = Match.group(1)
607
608 Match = re.match("^\s*#\s*@ValidList\s*(.+)\s*\|\s*(.+)\s*\|\s*(.+)\s*", DscLine)
609 if Match:
610 if Match.group(2).strip() in self._BuidinOption:
611 ConfigDict['option'] = Match.group(2).strip()
612 else:
613 OptionValueList = Match.group(2).split(',')
614 OptionStringList = Match.group(3).split(',')
615 Index = 0
616 for Option in OptionValueList:
617 Option = Option.strip()
618 ConfigDict['option'] = ConfigDict['option'] + str(Option) + ':' + OptionStringList[Index].strip()
619 Index += 1
620 if Index in range(len(OptionValueList)):
621 ConfigDict['option'] += ', '
622 ConfigDict['type'] = "Combo"
623
624 Match = re.match("^\s*#\s*@ValidRange\s*(.+)\s*\|\s*(.+)\s*-\s*(.+)\s*", DscLine)
625 if Match:
626 if "0x" in Match.group(2) or "0x" in Match.group(3):
627 ConfigDict['type'] = "EditNum, HEX, (%s,%s)" % (Match.group(2), Match.group(3))
628 else:
629 ConfigDict['type'] = "EditNum, DEC, (%s,%s)" % (Match.group(2), Match.group(3))
630
631 Match = re.match("^\s*##\s+(.+)", DscLine)
632 if Match:
633 ConfigDict['help'] = Match.group(1)
634
635 # Check VPD/UPD
636 if IsUpdSect:
637 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)
638 else:
639 Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)(?:\s*\|\s*(.+))?", DscLine)
640 if Match:
641 ConfigDict['space'] = Match.group(1)
642 ConfigDict['cname'] = Match.group(2)
643 if Match.group(3) != '*':
644 Hardcode = True
645 Offset = int (Match.group(3), 16)
646 else:
647 AutoAlign = True
648
649 if Hardcode and AutoAlign:
650 print("Hardcode and auto-align mixed mode is not supported by GenCfgOpt")
651 raise SystemExit
652 ConfigDict['offset'] = Offset
653 if ConfigDict['order'] == -1:
654 ConfigDict['order'] = ConfigDict['offset'] << 8
655 else:
656 (Major, Minor) = ConfigDict['order'].split('.')
657 ConfigDict['order'] = (int (Major, 16) << 8 ) + int (Minor, 16)
658 if IsUpdSect:
659 Value = Match.group(5).strip()
660 if Match.group(4).startswith("0x"):
661 Length = int (Match.group(4), 16)
662 else :
663 Length = int (Match.group(4))
664 Offset += Length
665 else:
666 Value = Match.group(4)
667 if Value is None:
668 Value = ''
669 Value = Value.strip()
670 if '|' in Value:
671 Match = re.match("^.+\s*\|\s*(.+)", Value)
672 if Match:
673 Value = Match.group(1)
674 Length = -1
675
676 ConfigDict['length'] = Length
677 Match = re.match("\$\((\w+)\)", Value)
678 if Match:
679 if Match.group(1) in self._MacroDict:
680 Value = self._MacroDict[Match.group(1)]
681
682 ConfigDict['value'] = Value
683 if (len(Value) > 0) and (Value[0] == '{'):
684 Value = self.FormatListValue(ConfigDict)
685
686 if ConfigDict['name'] == '':
687 # Clear BSF specific items
688 ConfigDict['bsfname'] = ''
689 ConfigDict['help'] = ''
690 ConfigDict['type'] = ''
691 ConfigDict['option'] = ''
692 if IsUpdSect and AutoAlign:
693 ItemLength = int(ConfigDict['length'])
694 ItemOffset = int(ConfigDict['offset'])
695 ItemStruct = ConfigDict['struct']
696 Unit = 1
697 if ItemLength in [1, 2, 4, 8] and not ConfigDict['value'].startswith('{'):
698 Unit = ItemLength
699 # If there are 64 bit unit, align to 64
700 if Unit == 8:
701 MaxAlign = 64
702 SizeAlign = 8
703 if ItemStruct != '':
704 UnitDict = {'UINT8':1, 'UINT16':2, 'UINT32':4, 'UINT64':8}
705 if ItemStruct in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
706 Unit = UnitDict[ItemStruct]
707 # If there are 64 bit unit, align to 64
708 if Unit == 8:
709 MaxAlign = 64
710 SizeAlign = max(SizeAlign, Unit)
711 if (ConfigDict['embed'].find(':START') != -1):
712 Base = ItemOffset
713 SubOffset = ItemOffset - Base
714 SubRemainder = SubOffset % Unit
715 if SubRemainder:
716 Diff = Unit - SubRemainder
717 Offset = Offset + Diff
718 ItemOffset = ItemOffset + Diff
719
720 if (ConfigDict['embed'].find(':END') != -1):
721 Remainder = Offset % (MaxAlign/8) # MaxAlign is either 32 or 64
722 if Remainder:
723 Diff = (MaxAlign/8) - Remainder
724 Offset = Offset + Diff
725 ItemOffset = ItemOffset + Diff
726 MaxAlign = 32 # Reset to default 32 align when struct end
727 if (ConfigDict['cname'] == 'UpdTerminator'):
728 # ItemLength is the size of UpdTerminator
729 # Itemlength might be 16, 32, or 64
730 # Struct align to 64 if UpdTerminator
731 # or struct size is 64 bit, else align to 32
732 Remainder = Offset % max(ItemLength/8, 4, SizeAlign)
733 Offset = Offset + ItemLength
734 if Remainder:
735 Diff = max(ItemLength/8, 4, SizeAlign) - Remainder
736 ItemOffset = ItemOffset + Diff
737 ConfigDict['offset'] = ItemOffset
738
739 self._CfgItemList.append(ConfigDict.copy())
740 ConfigDict['name'] = ''
741 ConfigDict['find'] = ''
742 ConfigDict['struct'] = ''
743 ConfigDict['embed'] = ''
744 ConfigDict['comment'] = ''
745 ConfigDict['order'] = -1
746 ConfigDict['subreg'] = []
747 ConfigDict['option'] = ''
748 else:
749 # It could be a virtual item as below
750 # !BSF FIELD:{SerialDebugPortAddress0:1}
751 # or
752 # @Bsf FIELD:{SerialDebugPortAddress0:1b}
753 Match = re.match("^\s*#\s+(!BSF|@Bsf)\s+FIELD:{(.+):(\d+)([Bb])?}", DscLine)
754 if Match:
755 SubCfgDict = ConfigDict.copy()
756 if (Match.group(4) == None) or (Match.group(4) == 'B'):
757 UnitBitLen = 8
758 elif Match.group(4) == 'b':
759 UnitBitLen = 1
760 else:
761 print("ERROR: Invalide BSF FIELD length for line '%s'" % DscLine)
762 raise SystemExit
763 SubCfgDict['cname'] = Match.group(2)
764 SubCfgDict['bitlength'] = int (Match.group(3)) * UnitBitLen
765 if SubCfgDict['bitlength'] > 0:
766 LastItem = self._CfgItemList[-1]
767 if len(LastItem['subreg']) == 0:
768 SubOffset = 0
769 else:
770 SubOffset = LastItem['subreg'][-1]['bitoffset'] + LastItem['subreg'][-1]['bitlength']
771 SubCfgDict['bitoffset'] = SubOffset
772 LastItem['subreg'].append (SubCfgDict.copy())
773 ConfigDict['name'] = ''
774 return Error
775
776 def GetBsfBitFields (self, subitem, bytes):
777 start = subitem['bitoffset']
778 end = start + subitem['bitlength']
779 bitsvalue = ''.join('{0:08b}'.format(i) for i in bytes[::-1])
780 bitsvalue = bitsvalue[::-1]
781 bitslen = len(bitsvalue)
782 if start > bitslen or end > bitslen:
783 print "Invalid bits offset [%d,%d] for %s" % (start, end, subitem['name'])
784 raise SystemExit
785 return hex(int(bitsvalue[start:end][::-1], 2))
786
787 def UpdateSubRegionDefaultValue (self):
788 Error = 0
789 for Item in self._CfgItemList:
790 if len(Item['subreg']) == 0:
791 continue
792 bytearray = []
793 if Item['value'][0] == '{':
794 binlist = Item['value'][1:-1].split(',')
795 for each in binlist:
796 each = each.strip()
797 if each.startswith('0x'):
798 value = int(each, 16)
799 else:
800 value = int(each)
801 bytearray.append(value)
802 else:
803 if Item['value'].startswith('0x'):
804 value = int(Item['value'], 16)
805 else:
806 value = int(Item['value'])
807 idx = 0
808 while idx < Item['length']:
809 bytearray.append(value & 0xFF)
810 value = value >> 8
811 idx = idx + 1
812 for SubItem in Item['subreg']:
813 valuestr = self.GetBsfBitFields(SubItem, bytearray)
814 SubItem['value'] = valuestr
815 return Error
816
817 def CreateSplitUpdTxt (self, UpdTxtFile):
818 GuidList = ['FSP_T_UPD_TOOL_GUID','FSP_M_UPD_TOOL_GUID','FSP_S_UPD_TOOL_GUID']
819 SignatureList = ['0x545F', '0x4D5F','0x535F'] # _T, _M, and _S signature for FSPT, FSPM, FSPS
820 for Index in range(len(GuidList)):
821 UpdTxtFile = ''
822 FvDir = self._FvDir
823 if GuidList[Index] not in self._MacroDict:
824 self.Error = "%s definition is missing in DSC file" % (GuidList[Index])
825 return 1
826
827 if UpdTxtFile == '':
828 UpdTxtFile = os.path.join(FvDir, self._MacroDict[GuidList[Index]] + '.txt')
829
830 ReCreate = False
831 if not os.path.exists(UpdTxtFile):
832 ReCreate = True
833 else:
834 DscTime = os.path.getmtime(self._DscFile)
835 TxtTime = os.path.getmtime(UpdTxtFile)
836 if DscTime > TxtTime:
837 ReCreate = True
838
839 if not ReCreate:
840 # DSC has not been modified yet
841 # So don't have to re-generate other files
842 self.Error = 'No DSC file change, skip to create UPD TXT file'
843 return 256
844
845 TxtFd = open(UpdTxtFile, "w")
846 TxtFd.write("%s\n" % (__copyright_txt__ % date.today().year))
847
848 NextOffset = 0
849 SpaceIdx = 0
850 StartAddr = 0
851 EndAddr = 0
852 Default = 'DEFAULT|'
853 InRange = False
854 for Item in self._CfgItemList:
855 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == SignatureList[Index]:
856 StartAddr = Item['offset']
857 NextOffset = StartAddr
858 InRange = True
859 if Item['cname'] == 'UpdTerminator' and InRange == True:
860 EndAddr = Item['offset']
861 InRange = False
862 InRange = False
863 for Item in self._CfgItemList:
864 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == SignatureList[Index]:
865 InRange = True
866 if InRange != True:
867 continue
868 if Item['cname'] == 'UpdTerminator':
869 InRange = False
870 if Item['region'] != 'UPD':
871 continue
872 Offset = Item['offset']
873 if StartAddr > Offset or EndAddr < Offset:
874 continue
875 if NextOffset < Offset:
876 # insert one line
877 TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset - StartAddr, Offset - NextOffset))
878 SpaceIdx = SpaceIdx + 1
879 NextOffset = Offset + Item['length']
880 TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'] - StartAddr,Item['length'],Item['value']))
881 TxtFd.close()
882 return 0
883
884 def ProcessMultilines (self, String, MaxCharLength):
885 Multilines = ''
886 StringLength = len(String)
887 CurrentStringStart = 0
888 StringOffset = 0
889 BreakLineDict = []
890 if len(String) <= MaxCharLength:
891 while (StringOffset < StringLength):
892 if StringOffset >= 1:
893 if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
894 BreakLineDict.append (StringOffset + 1)
895 StringOffset += 1
896 if BreakLineDict != []:
897 for Each in BreakLineDict:
898 Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip()
899 CurrentStringStart = Each
900 if StringLength - CurrentStringStart > 0:
901 Multilines += " %s\n" % String[CurrentStringStart:].lstrip()
902 else:
903 Multilines = " %s\n" % String
904 else:
905 NewLineStart = 0
906 NewLineCount = 0
907 FoundSpaceChar = False
908 while (StringOffset < StringLength):
909 if StringOffset >= 1:
910 if NewLineCount >= MaxCharLength - 1:
911 if String[StringOffset] == ' ' and StringLength - StringOffset > 10:
912 BreakLineDict.append (NewLineStart + NewLineCount)
913 NewLineStart = NewLineStart + NewLineCount
914 NewLineCount = 0
915 FoundSpaceChar = True
916 elif StringOffset == StringLength - 1 and FoundSpaceChar == False:
917 BreakLineDict.append (0)
918 if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
919 BreakLineDict.append (StringOffset + 1)
920 NewLineStart = StringOffset + 1
921 NewLineCount = 0
922 StringOffset += 1
923 NewLineCount += 1
924 if BreakLineDict != []:
925 BreakLineDict.sort ()
926 for Each in BreakLineDict:
927 if Each > 0:
928 Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip()
929 CurrentStringStart = Each
930 if StringLength - CurrentStringStart > 0:
931 Multilines += " %s\n" % String[CurrentStringStart:].lstrip()
932 return Multilines
933
934 def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help, Option):
935 PosName = 28
936 PosComment = 30
937 NameLine=''
938 HelpLine=''
939 OptionLine=''
940
941 IsArray = False
942 if Length in [1,2,4,8]:
943 Type = "UINT%d" % (Length * 8)
944 if Name.startswith("UnusedUpdSpace") and Length != 1:
945 IsArray = True
946 Type = "UINT8"
947 else:
948 IsArray = True
949 Type = "UINT8"
950
951 if Item and Item['value'].startswith('{'):
952 Type = "UINT8"
953 IsArray = True
954
955 if Struct != '':
956 Type = Struct
957 if Struct in ['UINT8','UINT16','UINT32','UINT64']:
958 IsArray = True
959 Unit = int(Type[4:]) / 8
960 Length = Length / Unit
961 else:
962 IsArray = False
963
964 if IsArray:
965 Name = Name + '[%d]' % Length
966
967 if len(Type) < PosName:
968 Space1 = PosName - len(Type)
969 else:
970 Space1 = 1
971
972 if BsfName != '':
973 NameLine=" - %s\n" % BsfName
974 else:
975 NameLine="\n"
976
977 if Help != '':
978 HelpLine = self.ProcessMultilines (Help, 80)
979
980 if Option != '':
981 OptionLine = self.ProcessMultilines (Option, 80)
982
983 if Offset is None:
984 OffsetStr = '????'
985 else:
986 OffsetStr = '0x%04X' % Offset
987
988 return "\n/** Offset %s%s%s%s**/\n %s%s%s;\n" % (OffsetStr, NameLine, HelpLine, OptionLine, Type, ' ' * Space1, Name,)
989
990 def PostProcessBody (self, TextBody):
991 NewTextBody = []
992 OldTextBody = []
993 IncludeLine = False
994 StructName = ''
995 VariableName = ''
996 IsUpdHdrDefined = False
997 IsUpdHeader = False
998 for Line in TextBody:
999 SplitToLines = Line.splitlines()
1000 MatchComment = re.match("^/\*\sCOMMENT:(\w+):([\w|\W|\s]+)\s\*/\s([\s\S]*)", SplitToLines[0])
1001 if MatchComment:
1002 if MatchComment.group(1) == 'FSP_UPD_HEADER':
1003 IsUpdHeader = True
1004 else:
1005 IsUpdHeader = False
1006 if IsUpdHdrDefined != True or IsUpdHeader != True:
1007 CommentLine = " " + MatchComment.group(2) + "\n"
1008 NewTextBody.append("/**" + CommentLine + "**/\n")
1009 Line = Line[(len(SplitToLines[0]) + 1):]
1010
1011 Match = re.match("^/\*\sEMBED_STRUCT:(\w+):(\w+):(START|END)\s\*/\s([\s\S]*)", Line)
1012 if Match:
1013 Line = Match.group(4)
1014 if Match.group(1) == 'FSP_UPD_HEADER':
1015 IsUpdHeader = True
1016 else:
1017 IsUpdHeader = False
1018
1019 if Match and Match.group(3) == 'START':
1020 if IsUpdHdrDefined != True or IsUpdHeader != True:
1021 NewTextBody.append ('typedef struct {\n')
1022 StructName = Match.group(1)
1023 VariableName = Match.group(2)
1024 MatchOffset = re.search('/\*\*\sOffset\s0x([a-fA-F0-9]+)', Line)
1025 if MatchOffset:
1026 Offset = int(MatchOffset.group(1), 16)
1027 else:
1028 Offset = None
1029 Line
1030 IncludeLine = True
1031 OldTextBody.append (self.CreateField (None, VariableName, 0, Offset, StructName, '', '', ''))
1032 if IncludeLine:
1033 if IsUpdHdrDefined != True or IsUpdHeader != True:
1034 NewTextBody.append (Line)
1035 else:
1036 OldTextBody.append (Line)
1037
1038 if Match and Match.group(3) == 'END':
1039 if (StructName != Match.group(1)) or (VariableName != Match.group(2)):
1040 print "Unmatched struct name '%s' and '%s' !" % (StructName, Match.group(1))
1041 else:
1042 if IsUpdHdrDefined != True or IsUpdHeader != True:
1043 NewTextBody.append ('} %s;\n\n' % StructName)
1044 IsUpdHdrDefined = True
1045 IncludeLine = False
1046 NewTextBody.extend(OldTextBody)
1047 return NewTextBody
1048
1049 def WriteLinesWithoutTailingSpace (self, HeaderFd, Line):
1050 TxtBody2 = Line.splitlines(True)
1051 for Line2 in TxtBody2:
1052 Line2 = Line2.rstrip()
1053 Line2 += '\n'
1054 HeaderFd.write (Line2)
1055 return 0
1056 def CreateHeaderFile (self, InputHeaderFile):
1057 FvDir = self._FvDir
1058
1059 HeaderFileName = 'FspUpd.h'
1060 HeaderFile = os.path.join(FvDir, HeaderFileName)
1061
1062 # Check if header needs to be recreated
1063 ReCreate = False
1064
1065 TxtBody = []
1066 for Item in self._CfgItemList:
1067 if str(Item['cname']) == 'Signature' and Item['length'] == 8:
1068 Value = int(Item['value'], 16)
1069 Chars = []
1070 while Value != 0x0:
1071 Chars.append(chr(Value & 0xFF))
1072 Value = Value >> 8
1073 SignatureStr = ''.join(Chars)
1074 # Signature will be _T / _M / _S for FSPT / FSPM / FSPS accordingly
1075 if '_T' in SignatureStr[6:6+2]:
1076 TxtBody.append("#define FSPT_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1077 elif '_M' in SignatureStr[6:6+2]:
1078 TxtBody.append("#define FSPM_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1079 elif '_S' in SignatureStr[6:6+2]:
1080 TxtBody.append("#define FSPS_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1081 TxtBody.append("\n")
1082
1083 for Region in ['UPD']:
1084 UpdOffsetTable = []
1085 UpdSignature = ['0x545F', '0x4D5F', '0x535F'] #['_T', '_M', '_S'] signature for FSPT, FSPM, FSPS
1086 UpdStructure = ['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD']
1087 for Item in self._CfgItemList:
1088 if Item["cname"] == 'Signature' and Item["value"][0:6] in UpdSignature:
1089 UpdOffsetTable.append (Item["offset"])
1090
1091 for UpdIdx in range(len(UpdOffsetTable)):
1092 CommentLine = ""
1093 for Item in self._CfgItemList:
1094 if Item["comment"] != '' and Item["offset"] >= UpdOffsetTable[UpdIdx]:
1095 MatchComment = re.match("^(U|V)PD_DATA_REGION:([\w|\W|\s]+)", Item["comment"])
1096 if MatchComment and MatchComment.group(1) == Region[0]:
1097 CommentLine = " " + MatchComment.group(2) + "\n"
1098 TxtBody.append("/**" + CommentLine + "**/\n")
1099 elif Item["offset"] >= UpdOffsetTable[UpdIdx] and Item["comment"] == '':
1100 Match = re.match("^FSP([\w|\W|\s])_UPD", UpdStructure[UpdIdx])
1101 if Match:
1102 TxtBody.append("/** Fsp " + Match.group(1) + " UPD Configuration\n**/\n")
1103 TxtBody.append("typedef struct {\n")
1104 NextOffset = 0
1105 SpaceIdx = 0
1106 Offset = 0
1107
1108 LastVisible = True
1109 ResvOffset = 0
1110 ResvIdx = 0
1111 LineBuffer = []
1112 InRange = False
1113 for Item in self._CfgItemList:
1114 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == UpdSignature[UpdIdx] or Region[0] == 'V':
1115 InRange = True
1116 if InRange != True:
1117 continue
1118 if Item['cname'] == 'UpdTerminator':
1119 InRange = False
1120
1121 if Item['region'] != Region:
1122 continue
1123
1124 if Item["offset"] < UpdOffsetTable[UpdIdx]:
1125 continue
1126
1127 NextVisible = LastVisible
1128
1129 if LastVisible and (Item['header'] == 'OFF'):
1130 NextVisible = False
1131 ResvOffset = Item['offset']
1132 elif (not LastVisible) and Item['header'] == 'ON':
1133 NextVisible = True
1134 Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx
1135 ResvIdx = ResvIdx + 1
1136 TxtBody.append(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, '', '', '', ''))
1137
1138 if Offset < Item["offset"]:
1139 if LastVisible:
1140 Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx
1141 LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, '', '', '', ''))
1142 SpaceIdx = SpaceIdx + 1
1143 Offset = Item["offset"]
1144
1145 LastVisible = NextVisible
1146
1147 Offset = Offset + Item["length"]
1148 if LastVisible:
1149 for Each in LineBuffer:
1150 TxtBody.append (Each)
1151 LineBuffer = []
1152 Comment = Item["comment"]
1153 Embed = Item["embed"].upper()
1154 if Embed.endswith(':START') or Embed.endswith(':END'):
1155 if not Comment == '' and Embed.endswith(':START'):
1156 Marker = '/* COMMENT:%s */ \n' % Item["comment"]
1157 Marker = Marker + '/* EMBED_STRUCT:%s */ ' % Item["embed"]
1158 else:
1159 Marker = '/* EMBED_STRUCT:%s */ ' % Item["embed"]
1160 else:
1161 if Embed == '':
1162 Marker = ''
1163 else:
1164 self.Error = "Invalid embedded structure format '%s'!\n" % Item["embed"]
1165 return 4
1166 Line = Marker + self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct'], Item['name'], Item['help'], Item['option'])
1167 TxtBody.append(Line)
1168 if Item['cname'] == 'UpdTerminator':
1169 break
1170 TxtBody.append("} " + UpdStructure[UpdIdx] + ";\n\n")
1171
1172 # Handle the embedded data structure
1173 TxtBody = self.PostProcessBody (TxtBody)
1174
1175 HeaderTFileName = 'FsptUpd.h'
1176 HeaderMFileName = 'FspmUpd.h'
1177 HeaderSFileName = 'FspsUpd.h'
1178
1179 UpdRegionCheck = ['FSPT', 'FSPM', 'FSPS'] # FSPX_UPD_REGION
1180 UpdConfigCheck = ['FSP_T', 'FSP_M', 'FSP_S'] # FSP_X_CONFIG, FSP_X_TEST_CONFIG, FSP_X_RESTRICTED_CONFIG
1181 UpdSignatureCheck = ['FSPT_UPD_SIGNATURE', 'FSPM_UPD_SIGNATURE', 'FSPS_UPD_SIGNATURE']
1182 ExcludedSpecificUpd = 'FSPM_ARCH_UPD'
1183
1184 if InputHeaderFile != '':
1185 if not os.path.exists(InputHeaderFile):
1186 self.Error = "Input header file '%s' does not exist" % InputHeaderFile
1187 return 6
1188
1189 InFd = open(InputHeaderFile, "r")
1190 IncLines = InFd.readlines()
1191 InFd.close()
1192
1193 for item in range(len(UpdRegionCheck)):
1194 if UpdRegionCheck[item] == 'FSPT':
1195 HeaderFd = open(os.path.join(FvDir, HeaderTFileName), "w")
1196 FileBase = os.path.basename(os.path.join(FvDir, HeaderTFileName))
1197 elif UpdRegionCheck[item] == 'FSPM':
1198 HeaderFd = open(os.path.join(FvDir, HeaderMFileName), "w")
1199 FileBase = os.path.basename(os.path.join(FvDir, HeaderMFileName))
1200 elif UpdRegionCheck[item] == 'FSPS':
1201 HeaderFd = open(os.path.join(FvDir, HeaderSFileName), "w")
1202 FileBase = os.path.basename(os.path.join(FvDir, HeaderSFileName))
1203 FileName = FileBase.replace(".", "_").upper()
1204 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
1205 HeaderFd.write("#ifndef __%s__\n" % FileName)
1206 HeaderFd.write("#define __%s__\n\n" % FileName)
1207 HeaderFd.write("#include <%s>\n\n" % HeaderFileName)
1208 HeaderFd.write("#pragma pack(1)\n\n")
1209
1210 Export = False
1211 for Line in IncLines:
1212 Match = re.search ("!EXPORT\s+([A-Z]+)\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line)
1213 if Match:
1214 if Match.group(2) == "BEGIN" and Match.group(1) == UpdRegionCheck[item]:
1215 Export = True
1216 continue
1217 else:
1218 Export = False
1219 continue
1220 if Export:
1221 HeaderFd.write(Line)
1222 HeaderFd.write("\n")
1223
1224 Index = 0
1225 StartIndex = 0
1226 EndIndex = 0
1227 StructStart = []
1228 StructStartWithComment = []
1229 StructEnd = []
1230 for Line in TxtBody:
1231 Index += 1
1232 Match = re.match("(typedef struct {)", Line)
1233 if Match:
1234 StartIndex = Index - 1
1235 Match = re.match("}\s([_A-Z0-9]+);", Line)
1236 if Match and (UpdRegionCheck[item] in Match.group(1) or UpdConfigCheck[item] in Match.group(1)) and (ExcludedSpecificUpd not in Match.group(1)):
1237 EndIndex = Index
1238 StructStart.append(StartIndex)
1239 StructEnd.append(EndIndex)
1240 Index = 0
1241 for Line in TxtBody:
1242 Index += 1
1243 for Item in range(len(StructStart)):
1244 if Index == StructStart[Item]:
1245 Match = re.match("^(/\*\*\s*)", Line)
1246 if Match:
1247 StructStartWithComment.append(StructStart[Item])
1248 else:
1249 StructStartWithComment.append(StructStart[Item] + 1)
1250 Index = 0
1251 for Line in TxtBody:
1252 Index += 1
1253 for Item in range(len(StructStart)):
1254 if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]:
1255 self.WriteLinesWithoutTailingSpace(HeaderFd, Line)
1256 HeaderFd.write("#pragma pack()\n\n")
1257 HeaderFd.write("#endif\n")
1258 HeaderFd.close()
1259
1260 HeaderFd = open(HeaderFile, "w")
1261 FileBase = os.path.basename(HeaderFile)
1262 FileName = FileBase.replace(".", "_").upper()
1263 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
1264 HeaderFd.write("#ifndef __%s__\n" % FileName)
1265 HeaderFd.write("#define __%s__\n\n" % FileName)
1266 HeaderFd.write("#include <FspEas.h>\n\n")
1267 HeaderFd.write("#pragma pack(1)\n\n")
1268
1269 for item in range(len(UpdRegionCheck)):
1270 Index = 0
1271 StartIndex = 0
1272 EndIndex = 0
1273 StructStart = []
1274 StructStartWithComment = []
1275 StructEnd = []
1276 for Line in TxtBody:
1277 Index += 1
1278 Match = re.match("(typedef struct {)", Line)
1279 if Match:
1280 StartIndex = Index - 1
1281 Match = re.match("#define\s([_A-Z0-9]+)\s*", Line)
1282 if Match and (UpdSignatureCheck[item] in Match.group(1) or UpdSignatureCheck[item] in Match.group(1)):
1283 StructStart.append(Index - 1)
1284 StructEnd.append(Index)
1285 Index = 0
1286 for Line in TxtBody:
1287 Index += 1
1288 for Item in range(len(StructStart)):
1289 if Index == StructStart[Item]:
1290 Match = re.match("^(/\*\*\s*)", Line)
1291 if Match:
1292 StructStartWithComment.append(StructStart[Item])
1293 else:
1294 StructStartWithComment.append(StructStart[Item] + 1)
1295 Index = 0
1296 for Line in TxtBody:
1297 Index += 1
1298 for Item in range(len(StructStart)):
1299 if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]:
1300 self.WriteLinesWithoutTailingSpace(HeaderFd, Line)
1301 HeaderFd.write("#pragma pack()\n\n")
1302 HeaderFd.write("#endif\n")
1303 HeaderFd.close()
1304
1305 return 0
1306
1307 def WriteBsfStruct (self, BsfFd, Item):
1308 LogExpr = CLogicalExpression()
1309 if Item['type'] == "None":
1310 Space = "gPlatformFspPkgTokenSpaceGuid"
1311 else:
1312 Space = Item['space']
1313 Line = " $%s_%s" % (Space, Item['cname'])
1314 Match = re.match("\s*\{([x0-9a-fA-F,\s]+)\}\s*", Item['value'])
1315 if Match:
1316 DefaultValue = Match.group(1).strip()
1317 else:
1318 DefaultValue = Item['value'].strip()
1319 if 'bitlength' in Item:
1320 BsfFd.write(" %s%s%4d bits $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['bitlength'], DefaultValue))
1321 else:
1322 BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue))
1323 TmpList = []
1324 if Item['type'] == "Combo":
1325 if not Item['option'] in self._BuidinOption:
1326 OptList = Item['option'].split(',')
1327 for Option in OptList:
1328 Option = Option.strip()
1329 (OpVal, OpStr) = Option.split(':')
1330 test = LogExpr.getNumber (OpVal)
1331 if test is None:
1332 raise Exception("Selection Index '%s' is not a number" % OpVal)
1333 TmpList.append((OpVal, OpStr))
1334 return TmpList
1335
1336 def WriteBsfOption (self, BsfFd, Item):
1337 PcdName = Item['space'] + '_' + Item['cname']
1338 WriteHelp = 0
1339 if Item['type'] == "Combo":
1340 if Item['option'] in self._BuidinOption:
1341 Options = self._BuidinOption[Item['option']]
1342 else:
1343 Options = PcdName
1344 BsfFd.write(' %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options))
1345 WriteHelp = 1
1346 elif Item['type'].startswith("EditNum"):
1347 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'])
1348 if Match:
1349 BsfFd.write(' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1)))
1350 WriteHelp = 2
1351 elif Item['type'].startswith("EditText"):
1352 BsfFd.write(' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name']))
1353 WriteHelp = 1
1354 elif Item['type'] == "Table":
1355 Columns = Item['option'].split(',')
1356 if len(Columns) != 0:
1357 BsfFd.write(' %s $%s "%s",' % (Item['type'], PcdName, Item['name']))
1358 for Col in Columns:
1359 Fmt = Col.split(':')
1360 if len(Fmt) != 3:
1361 raise Exception("Column format '%s' is invalid !" % Fmt)
1362 try:
1363 Dtype = int(Fmt[1].strip())
1364 except:
1365 raise Exception("Column size '%s' is invalid !" % Fmt[1])
1366 BsfFd.write('\n Column "%s", %d bytes, %s' % (Fmt[0].strip(), Dtype, Fmt[2].strip()))
1367 BsfFd.write(',\n')
1368 WriteHelp = 1
1369
1370 if WriteHelp > 0:
1371 HelpLines = Item['help'].split('\\n\\r')
1372 FirstLine = True
1373 for HelpLine in HelpLines:
1374 if FirstLine:
1375 FirstLine = False
1376 BsfFd.write(' Help "%s"\n' % (HelpLine))
1377 else:
1378 BsfFd.write(' "%s"\n' % (HelpLine))
1379 if WriteHelp == 2:
1380 BsfFd.write(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3)))
1381
1382 def GenerateBsfFile (self, BsfFile):
1383
1384 if BsfFile == '':
1385 self.Error = "BSF output file '%s' is invalid" % BsfFile
1386 return 1
1387
1388 Error = 0
1389 OptionDict = {}
1390 BsfFd = open(BsfFile, "w")
1391 BsfFd.write("%s\n" % (__copyright_bsf__ % date.today().year))
1392 BsfFd.write("%s\n" % self._GlobalDataDef)
1393 BsfFd.write("StructDef\n")
1394 NextOffset = -1
1395 for Item in self._CfgItemList:
1396 if Item['find'] != '':
1397 BsfFd.write('\n Find "%s"\n' % Item['find'])
1398 NextOffset = Item['offset'] + Item['length']
1399 if Item['name'] != '':
1400 if NextOffset != Item['offset']:
1401 BsfFd.write(" Skip %d bytes\n" % (Item['offset'] - NextOffset))
1402 if len(Item['subreg']) > 0:
1403 NextOffset = Item['offset']
1404 BitsOffset = NextOffset * 8
1405 for SubItem in Item['subreg']:
1406 BitsOffset += SubItem['bitlength']
1407 if SubItem['name'] == '':
1408 if 'bitlength' in SubItem:
1409 BsfFd.write(" Skip %d bits\n" % (SubItem['bitlength']))
1410 else:
1411 BsfFd.write(" Skip %d bytes\n" % (SubItem['length']))
1412 else:
1413 Options = self.WriteBsfStruct(BsfFd, SubItem)
1414 if len(Options) > 0:
1415 OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options
1416
1417 NextBitsOffset = (Item['offset'] + Item['length']) * 8
1418 if NextBitsOffset > BitsOffset:
1419 BitsGap = NextBitsOffset - BitsOffset
1420 BitsRemain = BitsGap % 8
1421 if BitsRemain:
1422 BsfFd.write(" Skip %d bits\n" % BitsRemain)
1423 BitsGap -= BitsRemain
1424 BytesRemain = BitsGap / 8
1425 if BytesRemain:
1426 BsfFd.write(" Skip %d bytes\n" % BytesRemain)
1427 NextOffset = Item['offset'] + Item['length']
1428 else:
1429 NextOffset = Item['offset'] + Item['length']
1430 Options = self.WriteBsfStruct(BsfFd, Item)
1431 if len(Options) > 0:
1432 OptionDict[Item['space']+'_'+Item['cname']] = Options
1433 BsfFd.write("\nEndStruct\n\n")
1434
1435 BsfFd.write("%s" % self._BuidinOptionTxt)
1436
1437 for Each in OptionDict:
1438 BsfFd.write("List &%s\n" % Each)
1439 for Item in OptionDict[Each]:
1440 BsfFd.write(' Selection %s , "%s"\n' % (Item[0], Item[1]))
1441 BsfFd.write("EndList\n\n")
1442
1443 BsfFd.write("BeginInfoBlock\n")
1444 BsfFd.write(' PPVer "%s"\n' % (self._CfgBlkDict['ver']))
1445 BsfFd.write(' Description "%s"\n' % (self._CfgBlkDict['name']))
1446 BsfFd.write("EndInfoBlock\n\n")
1447
1448 for Each in self._CfgPageDict:
1449 BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each])
1450 BsfItems = []
1451 for Item in self._CfgItemList:
1452 if Item['name'] != '':
1453 if Item['page'] != Each:
1454 continue
1455 if len(Item['subreg']) > 0:
1456 for SubItem in Item['subreg']:
1457 if SubItem['name'] != '':
1458 BsfItems.append(SubItem)
1459 else:
1460 BsfItems.append(Item)
1461
1462 BsfItems.sort(key=lambda x: x['order'])
1463
1464 for Item in BsfItems:
1465 self.WriteBsfOption (BsfFd, Item)
1466 BsfFd.write("EndPage\n\n")
1467
1468 BsfFd.close()
1469 return Error
1470
1471
1472 def Usage():
1473 print "GenCfgOpt Version 0.53"
1474 print "Usage:"
1475 print " GenCfgOpt UPDTXT PlatformDscFile BuildFvDir [-D Macros]"
1476 print " GenCfgOpt HEADER PlatformDscFile BuildFvDir InputHFile [-D Macros]"
1477 print " GenCfgOpt GENBSF PlatformDscFile BuildFvDir BsfOutFile [-D Macros]"
1478
1479 def Main():
1480 #
1481 # Parse the options and args
1482 #
1483 i = 1
1484
1485 GenCfgOpt = CGenCfgOpt()
1486 while i < len(sys.argv):
1487 if sys.argv[i].strip().lower() == "--pcd":
1488 BuildOptionPcd.append(sys.argv[i+1])
1489 i += 1
1490 i += 1
1491 argc = len(sys.argv)
1492 if argc < 4:
1493 Usage()
1494 return 1
1495 else:
1496 DscFile = sys.argv[2]
1497 if not os.path.exists(DscFile):
1498 print "ERROR: Cannot open DSC file '%s' !" % DscFile
1499 return 2
1500
1501 OutFile = ''
1502 if argc > 4:
1503 if sys.argv[4][0] == '-':
1504 Start = 4
1505 else:
1506 OutFile = sys.argv[4]
1507 Start = 5
1508 if argc > Start:
1509 if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:
1510 print "ERROR: Macro parsing failed !"
1511 return 3
1512
1513 FvDir = sys.argv[3]
1514 if not os.path.exists(FvDir):
1515 os.makedirs(FvDir)
1516
1517 if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:
1518 print "ERROR: %s !" % GenCfgOpt.Error
1519 return 5
1520
1521 if GenCfgOpt.UpdateSubRegionDefaultValue() != 0:
1522 print "ERROR: %s !" % GenCfgOpt.Error
1523 return 7
1524
1525 if sys.argv[1] == "UPDTXT":
1526 Ret = GenCfgOpt.CreateSplitUpdTxt(OutFile)
1527 if Ret != 0:
1528 # No change is detected
1529 if Ret == 256:
1530 print "INFO: %s !" % (GenCfgOpt.Error)
1531 else :
1532 print "ERROR: %s !" % (GenCfgOpt.Error)
1533 return Ret
1534 elif sys.argv[1] == "HEADER":
1535 if GenCfgOpt.CreateHeaderFile(OutFile) != 0:
1536 print "ERROR: %s !" % GenCfgOpt.Error
1537 return 8
1538 elif sys.argv[1] == "GENBSF":
1539 if GenCfgOpt.GenerateBsfFile(OutFile) != 0:
1540 print "ERROR: %s !" % GenCfgOpt.Error
1541 return 9
1542 else:
1543 if argc < 5:
1544 Usage()
1545 return 1
1546 print "ERROR: Unknown command '%s' !" % sys.argv[1]
1547 Usage()
1548 return 1
1549 return 0
1550 return 0
1551
1552
1553 if __name__ == '__main__':
1554 sys.exit(Main())