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