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