]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/GenCfgOpt.py
BaseTools/Ecc: Fix ECC check MetaFile Copyright information issue
[mirror_edk2.git] / IntelFsp2Pkg / Tools / GenCfgOpt.py
1 ## @ GenCfgOpt.py
2 #
3 # Copyright (c) 2014 - 2020, 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 Base = 0 #Starting offset of sub-structure.
443 while len(DscLines):
444 DscLine = DscLines.pop(0).strip()
445 Handle = False
446 Match = re.match("^\[(.+)\]", DscLine)
447 if Match is not None:
448 IsDefSect = False
449 IsPcdSect = False
450 IsVpdSect = False
451 IsUpdSect = False
452 if Match.group(1).lower() == "Defines".lower():
453 IsDefSect = True
454 if (Match.group(1).lower() == "PcdsFeatureFlag".lower() or Match.group(1).lower() == "PcdsFixedAtBuild".lower()):
455 IsPcdSect = True
456 elif Match.group(1).lower() == "PcdsDynamicVpd.Upd".lower():
457 ConfigDict = {}
458 ConfigDict['header'] = 'ON'
459 ConfigDict['region'] = 'UPD'
460 ConfigDict['order'] = -1
461 ConfigDict['page'] = ''
462 ConfigDict['name'] = ''
463 ConfigDict['find'] = ''
464 ConfigDict['struct'] = ''
465 ConfigDict['embed'] = ''
466 ConfigDict['comment'] = ''
467 ConfigDict['subreg'] = []
468 IsUpdSect = True
469 Offset = 0
470 else:
471 if IsDefSect or IsPcdSect or IsUpdSect or IsVpdSect:
472 if re.match("^!else($|\s+#.+)", DscLine):
473 if IfStack:
474 IfStack[-1] = not IfStack[-1]
475 else:
476 print("ERROR: No paired '!if' found for '!else' for line '%s'" % DscLine)
477 raise SystemExit
478 elif re.match("^!endif($|\s+#.+)", DscLine):
479 if IfStack:
480 IfStack.pop()
481 Level = ElifStack.pop()
482 if Level > 0:
483 del IfStack[-Level:]
484 else:
485 print("ERROR: No paired '!if' found for '!endif' for line '%s'" % DscLine)
486 raise SystemExit
487 else:
488 Result = False
489 Match = re.match("!(ifdef|ifndef)\s+(.+)", DscLine)
490 if Match:
491 Result = self.EvaulateIfdef (Match.group(2))
492 if Match.group(1) == 'ifndef':
493 Result = not Result
494 IfStack.append(Result)
495 ElifStack.append(0)
496 else:
497 Match = re.match("!(if|elseif)\s+(.+)", DscLine.split("#")[0])
498 if Match:
499 Result = self.EvaluateExpress(Match.group(2))
500 if Match.group(1) == "if":
501 ElifStack.append(0)
502 IfStack.append(Result)
503 else: #elseif
504 if IfStack:
505 IfStack[-1] = not IfStack[-1]
506 IfStack.append(Result)
507 ElifStack[-1] = ElifStack[-1] + 1
508 else:
509 print("ERROR: No paired '!if' found for '!elif' for line '%s'" % DscLine)
510 raise SystemExit
511 else:
512 if IfStack:
513 Handle = reduce(lambda x,y: x and y, IfStack)
514 else:
515 Handle = True
516 if Handle:
517 Match = re.match("!include\s+(.+)", DscLine)
518 if Match:
519 IncludeFilePath = Match.group(1)
520 IncludeFilePath = self.ExpandMacros(IncludeFilePath)
521 PackagesPath = os.getenv("PACKAGES_PATH")
522 if PackagesPath:
523 for PackagePath in PackagesPath.split(os.pathsep):
524 IncludeFilePathAbs = os.path.join(os.path.normpath(PackagePath), os.path.normpath(IncludeFilePath))
525 if os.path.exists(IncludeFilePathAbs):
526 IncludeDsc = open(IncludeFilePathAbs, "r")
527 break
528 else:
529 IncludeDsc = open(IncludeFilePath, "r")
530 if IncludeDsc == None:
531 print("ERROR: Cannot open file '%s'" % IncludeFilePath)
532 raise SystemExit
533 NewDscLines = IncludeDsc.readlines()
534 IncludeDsc.close()
535 DscLines = NewDscLines + DscLines
536 Offset = 0
537 else:
538 if DscLine.startswith('!'):
539 print("ERROR: Unrecognized directive for line '%s'" % DscLine)
540 raise SystemExit
541 if not Handle:
542 continue
543
544 if IsDefSect:
545 #DEFINE UPD_TOOL_GUID = 8C3D856A-9BE6-468E-850A-24F7A8D38E09
546 #DEFINE FSP_T_UPD_TOOL_GUID = 34686CA3-34F9-4901-B82A-BA630F0714C6
547 #DEFINE FSP_M_UPD_TOOL_GUID = 39A250DB-E465-4DD1-A2AC-E2BD3C0E2385
548 #DEFINE FSP_S_UPD_TOOL_GUID = CAE3605B-5B34-4C85-B3D7-27D54273C40F
549 Match = re.match("^\s*(?:DEFINE\s+)*(\w+)\s*=\s*([/$()-.\w]+)", DscLine)
550 if Match:
551 self._MacroDict[Match.group(1)] = self.ExpandMacros(Match.group(2))
552 if self.Debug:
553 print ("INFO : DEFINE %s = [ %s ]" % (Match.group(1), self.ExpandMacros(Match.group(2))))
554 elif IsPcdSect:
555 #gSiPkgTokenSpaceGuid.PcdTxtEnable|FALSE
556 #gSiPkgTokenSpaceGuid.PcdOverclockEnable|TRUE
557 Match = re.match("^\s*([\w\.]+)\s*\|\s*(\w+)", DscLine)
558 if Match:
559 self._PcdsDict[Match.group(1)] = Match.group(2)
560 if self.Debug:
561 print ("INFO : PCD %s = [ %s ]" % (Match.group(1), Match.group(2)))
562 i = 0
563 while i < len(BuildOptionPcd):
564 Match = re.match("\s*([\w\.]+)\s*\=\s*(\w+)", BuildOptionPcd[i])
565 if Match:
566 self._PcdsDict[Match.group(1)] = Match.group(2)
567 i += 1
568 else:
569 Match = re.match("^\s*#\s+(!BSF|@Bsf|!HDR)\s+(.+)", DscLine)
570 if Match:
571 Remaining = Match.group(2)
572 if Match.group(1) == '!BSF' or Match.group(1) == '@Bsf':
573 Match = re.match("(?:^|.+\s+)PAGES:{(.+?)}", Remaining)
574 if Match:
575 # !BSF PAGES:{HSW:"Haswell System Agent", LPT:"Lynx Point PCH"}
576 PageList = Match.group(1).split(',')
577 for Page in PageList:
578 Page = Page.strip()
579 Match = re.match("(\w+):\"(.+)\"", Page)
580 self._CfgPageDict[Match.group(1)] = Match.group(2)
581
582 Match = re.match("(?:^|.+\s+)BLOCK:{NAME:\"(.+)\"\s*,\s*VER:\"(.+)\"\s*}", Remaining)
583 if Match:
584 self._CfgBlkDict['name'] = Match.group(1)
585 self._CfgBlkDict['ver'] = Match.group(2)
586
587 for Key in self._BsfKeyList:
588 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
589 if Match:
590 if Key in ['NAME', 'HELP', 'OPTION'] and Match.group(1).startswith('+'):
591 ConfigDict[Key.lower()] += Match.group(1)[1:]
592 else:
593 ConfigDict[Key.lower()] = Match.group(1)
594 else:
595 for Key in self._HdrKeyList:
596 Match = re.match("(?:^|.+\s+)%s:{(.+?)}" % Key, Remaining)
597 if Match:
598 ConfigDict[Key.lower()] = Match.group(1)
599
600 Match = re.match("^\s*#\s+@Prompt\s+(.+)", DscLine)
601 if Match:
602 ConfigDict['name'] = Match.group(1)
603
604 Match = re.match("^\s*#\s*@ValidList\s*(.+)\s*\|\s*(.+)\s*\|\s*(.+)\s*", DscLine)
605 if Match:
606 if Match.group(2).strip() in self._BuidinOption:
607 ConfigDict['option'] = Match.group(2).strip()
608 else:
609 OptionValueList = Match.group(2).split(',')
610 OptionStringList = Match.group(3).split(',')
611 Index = 0
612 for Option in OptionValueList:
613 Option = Option.strip()
614 ConfigDict['option'] = ConfigDict['option'] + str(Option) + ':' + OptionStringList[Index].strip()
615 Index += 1
616 if Index in range(len(OptionValueList)):
617 ConfigDict['option'] += ', '
618 ConfigDict['type'] = "Combo"
619
620 Match = re.match("^\s*#\s*@ValidRange\s*(.+)\s*\|\s*(.+)\s*-\s*(.+)\s*", DscLine)
621 if Match:
622 if "0x" in Match.group(2) or "0x" in Match.group(3):
623 ConfigDict['type'] = "EditNum, HEX, (%s,%s)" % (Match.group(2), Match.group(3))
624 else:
625 ConfigDict['type'] = "EditNum, DEC, (%s,%s)" % (Match.group(2), Match.group(3))
626
627 Match = re.match("^\s*##\s+(.+)", DscLine)
628 if Match:
629 ConfigDict['help'] = Match.group(1)
630
631 # Check VPD/UPD
632 if IsUpdSect:
633 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)
634 else:
635 Match = re.match("^([_a-zA-Z0-9]+).([_a-zA-Z0-9]+)\s*\|\s*(0x[0-9A-F]+)(?:\s*\|\s*(.+))?", DscLine)
636 if Match:
637 ConfigDict['space'] = Match.group(1)
638 ConfigDict['cname'] = Match.group(2)
639 if Match.group(3) != '*':
640 Hardcode = True
641 Offset = int (Match.group(3), 16)
642 else:
643 AutoAlign = True
644
645 if Hardcode and AutoAlign:
646 print("Hardcode and auto-align mixed mode is not supported by GenCfgOpt")
647 raise SystemExit
648 ConfigDict['offset'] = Offset
649 if ConfigDict['order'] == -1:
650 ConfigDict['order'] = ConfigDict['offset'] << 8
651 else:
652 (Major, Minor) = ConfigDict['order'].split('.')
653 ConfigDict['order'] = (int (Major, 16) << 8 ) + int (Minor, 16)
654 if IsUpdSect:
655 Value = Match.group(5).strip()
656 if Match.group(4).startswith("0x"):
657 Length = int (Match.group(4), 16)
658 else :
659 Length = int (Match.group(4))
660 Offset += Length
661 else:
662 Value = Match.group(4)
663 if Value is None:
664 Value = ''
665 Value = Value.strip()
666 if '|' in Value:
667 Match = re.match("^.+\s*\|\s*(.+)", Value)
668 if Match:
669 Value = Match.group(1)
670 Length = -1
671
672 ConfigDict['length'] = Length
673 Match = re.match("\$\((\w+)\)", Value)
674 if Match:
675 if Match.group(1) in self._MacroDict:
676 Value = self._MacroDict[Match.group(1)]
677
678 ConfigDict['value'] = Value
679 if (len(Value) > 0) and (Value[0] == '{'):
680 Value = self.FormatListValue(ConfigDict)
681
682 if ConfigDict['name'] == '':
683 # Clear BSF specific items
684 ConfigDict['bsfname'] = ''
685 ConfigDict['help'] = ''
686 ConfigDict['type'] = ''
687 ConfigDict['option'] = ''
688 if IsUpdSect and AutoAlign:
689 ItemLength = int(ConfigDict['length'])
690 ItemOffset = int(ConfigDict['offset'])
691 ItemStruct = ConfigDict['struct']
692 Unit = 1
693 if ItemLength in [1, 2, 4, 8] and not ConfigDict['value'].startswith('{'):
694 Unit = ItemLength
695 # If there are 64 bit unit, align to 64
696 if Unit == 8:
697 MaxAlign = 64
698 SizeAlign = 8
699 if ItemStruct != '':
700 UnitDict = {'UINT8':1, 'UINT16':2, 'UINT32':4, 'UINT64':8}
701 if ItemStruct in ['UINT8', 'UINT16', 'UINT32', 'UINT64']:
702 Unit = UnitDict[ItemStruct]
703 # If there are 64 bit unit, align to 64
704 if Unit == 8:
705 MaxAlign = 64
706 SizeAlign = max(SizeAlign, Unit)
707 if (ConfigDict['embed'].find(':START') != -1):
708 Base = ItemOffset
709 SubOffset = ItemOffset - Base
710 SubRemainder = SubOffset % Unit
711 if SubRemainder:
712 Diff = Unit - SubRemainder
713 Offset = Offset + Diff
714 ItemOffset = ItemOffset + Diff
715
716 if (ConfigDict['embed'].find(':END') != -1):
717 Remainder = Offset % (MaxAlign/8) # MaxAlign is either 32 or 64
718 if Remainder:
719 Diff = int((MaxAlign/8) - Remainder)
720 Offset = Offset + Diff
721 ItemOffset = ItemOffset + Diff
722 MaxAlign = 32 # Reset to default 32 align when struct end
723 if (ConfigDict['cname'] == 'UpdTerminator'):
724 # ItemLength is the size of UpdTerminator
725 # Itemlength might be 16, 32, or 64
726 # Struct align to 64 if UpdTerminator
727 # or struct size is 64 bit, else align to 32
728 Remainder = Offset % max(ItemLength/8, 4, SizeAlign)
729 Offset = Offset + ItemLength
730 if Remainder:
731 Diff = int(max(ItemLength/8, 4, SizeAlign) - Remainder)
732 ItemOffset = ItemOffset + Diff
733 ConfigDict['offset'] = ItemOffset
734
735 self._CfgItemList.append(ConfigDict.copy())
736 ConfigDict['name'] = ''
737 ConfigDict['find'] = ''
738 ConfigDict['struct'] = ''
739 ConfigDict['embed'] = ''
740 ConfigDict['comment'] = ''
741 ConfigDict['order'] = -1
742 ConfigDict['subreg'] = []
743 ConfigDict['option'] = ''
744 else:
745 # It could be a virtual item as below
746 # !BSF FIELD:{SerialDebugPortAddress0:1}
747 # or
748 # @Bsf FIELD:{SerialDebugPortAddress0:1b}
749 Match = re.match("^\s*#\s+(!BSF|@Bsf)\s+FIELD:{(.+):(\d+)([Bb])?}", DscLine)
750 if Match:
751 SubCfgDict = ConfigDict.copy()
752 if (Match.group(4) == None) or (Match.group(4) == 'B'):
753 UnitBitLen = 8
754 elif Match.group(4) == 'b':
755 UnitBitLen = 1
756 else:
757 print("ERROR: Invalide BSF FIELD length for line '%s'" % DscLine)
758 raise SystemExit
759 SubCfgDict['cname'] = Match.group(2)
760 SubCfgDict['bitlength'] = int (Match.group(3)) * UnitBitLen
761 if SubCfgDict['bitlength'] > 0:
762 LastItem = self._CfgItemList[-1]
763 if len(LastItem['subreg']) == 0:
764 SubOffset = 0
765 else:
766 SubOffset = LastItem['subreg'][-1]['bitoffset'] + LastItem['subreg'][-1]['bitlength']
767 SubCfgDict['bitoffset'] = SubOffset
768 LastItem['subreg'].append (SubCfgDict.copy())
769 ConfigDict['name'] = ''
770 return Error
771
772 def GetBsfBitFields (self, subitem, bytes):
773 start = subitem['bitoffset']
774 end = start + subitem['bitlength']
775 bitsvalue = ''.join('{0:08b}'.format(i) for i in bytes[::-1])
776 bitsvalue = bitsvalue[::-1]
777 bitslen = len(bitsvalue)
778 if start > bitslen or end > bitslen:
779 print ("Invalid bits offset [%d,%d] for %s" % (start, end, subitem['name']))
780 raise SystemExit
781 return hex(int(bitsvalue[start:end][::-1], 2))
782
783 def UpdateSubRegionDefaultValue (self):
784 Error = 0
785 for Item in self._CfgItemList:
786 if len(Item['subreg']) == 0:
787 continue
788 bytearray = []
789 if Item['value'][0] == '{':
790 binlist = Item['value'][1:-1].split(',')
791 for each in binlist:
792 each = each.strip()
793 if each.startswith('0x'):
794 value = int(each, 16)
795 else:
796 value = int(each)
797 bytearray.append(value)
798 else:
799 if Item['value'].startswith('0x'):
800 value = int(Item['value'], 16)
801 else:
802 value = int(Item['value'])
803 idx = 0
804 while idx < Item['length']:
805 bytearray.append(value & 0xFF)
806 value = value >> 8
807 idx = idx + 1
808 for SubItem in Item['subreg']:
809 valuestr = self.GetBsfBitFields(SubItem, bytearray)
810 SubItem['value'] = valuestr
811 return Error
812
813 def NoDscFileChange (self, OutPutFile):
814 NoFileChange = True
815 if not os.path.exists(OutPutFile):
816 NoFileChange = False
817 else:
818 DscTime = os.path.getmtime(self._DscFile)
819 OutputTime = os.path.getmtime(OutPutFile)
820 if DscTime > OutputTime:
821 NoFileChange = False
822 return NoFileChange
823
824 def CreateSplitUpdTxt (self, UpdTxtFile):
825 GuidList = ['FSP_T_UPD_TOOL_GUID','FSP_M_UPD_TOOL_GUID','FSP_S_UPD_TOOL_GUID']
826 SignatureList = ['0x545F', '0x4D5F','0x535F'] # _T, _M, and _S signature for FSPT, FSPM, FSPS
827 for Index in range(len(GuidList)):
828 UpdTxtFile = ''
829 FvDir = self._FvDir
830 if GuidList[Index] not in self._MacroDict:
831 self.Error = "%s definition is missing in DSC file" % (GuidList[Index])
832 return 1
833
834 if UpdTxtFile == '':
835 UpdTxtFile = os.path.join(FvDir, self._MacroDict[GuidList[Index]] + '.txt')
836
837 if (self.NoDscFileChange (UpdTxtFile)):
838 # DSC has not been modified yet
839 # So don't have to re-generate other files
840 self.Error = 'No DSC file change, skip to create UPD TXT file'
841 return 256
842
843 TxtFd = open(UpdTxtFile, "w")
844 TxtFd.write("%s\n" % (__copyright_txt__ % date.today().year))
845
846 NextOffset = 0
847 SpaceIdx = 0
848 StartAddr = 0
849 EndAddr = 0
850 Default = 'DEFAULT|'
851 InRange = False
852 for Item in self._CfgItemList:
853 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == SignatureList[Index]:
854 StartAddr = Item['offset']
855 NextOffset = StartAddr
856 InRange = True
857 if Item['cname'] == 'UpdTerminator' and InRange == True:
858 EndAddr = Item['offset']
859 InRange = False
860 InRange = False
861 for Item in self._CfgItemList:
862 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == SignatureList[Index]:
863 InRange = True
864 if InRange != True:
865 continue
866 if Item['cname'] == 'UpdTerminator':
867 InRange = False
868 if Item['region'] != 'UPD':
869 continue
870 Offset = Item['offset']
871 if StartAddr > Offset or EndAddr < Offset:
872 continue
873 if NextOffset < Offset:
874 # insert one line
875 TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset - StartAddr, Offset - NextOffset))
876 SpaceIdx = SpaceIdx + 1
877 NextOffset = Offset + Item['length']
878 TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'] - StartAddr,Item['length'],Item['value']))
879 TxtFd.close()
880 return 0
881
882 def ProcessMultilines (self, String, MaxCharLength):
883 Multilines = ''
884 StringLength = len(String)
885 CurrentStringStart = 0
886 StringOffset = 0
887 BreakLineDict = []
888 if len(String) <= MaxCharLength:
889 while (StringOffset < StringLength):
890 if StringOffset >= 1:
891 if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
892 BreakLineDict.append (StringOffset + 1)
893 StringOffset += 1
894 if BreakLineDict != []:
895 for Each in BreakLineDict:
896 Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip()
897 CurrentStringStart = Each
898 if StringLength - CurrentStringStart > 0:
899 Multilines += " %s\n" % String[CurrentStringStart:].lstrip()
900 else:
901 Multilines = " %s\n" % String
902 else:
903 NewLineStart = 0
904 NewLineCount = 0
905 FoundSpaceChar = False
906 while (StringOffset < StringLength):
907 if StringOffset >= 1:
908 if NewLineCount >= MaxCharLength - 1:
909 if String[StringOffset] == ' ' and StringLength - StringOffset > 10:
910 BreakLineDict.append (NewLineStart + NewLineCount)
911 NewLineStart = NewLineStart + NewLineCount
912 NewLineCount = 0
913 FoundSpaceChar = True
914 elif StringOffset == StringLength - 1 and FoundSpaceChar == False:
915 BreakLineDict.append (0)
916 if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
917 BreakLineDict.append (StringOffset + 1)
918 NewLineStart = StringOffset + 1
919 NewLineCount = 0
920 StringOffset += 1
921 NewLineCount += 1
922 if BreakLineDict != []:
923 BreakLineDict.sort ()
924 for Each in BreakLineDict:
925 if Each > 0:
926 Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip()
927 CurrentStringStart = Each
928 if StringLength - CurrentStringStart > 0:
929 Multilines += " %s\n" % String[CurrentStringStart:].lstrip()
930 return Multilines
931
932 def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help, Option):
933 PosName = 28
934 PosComment = 30
935 NameLine=''
936 HelpLine=''
937 OptionLine=''
938
939 IsArray = False
940 if Length in [1,2,4,8]:
941 Type = "UINT%d" % (Length * 8)
942 if Name.startswith("UnusedUpdSpace") and Length != 1:
943 IsArray = True
944 Type = "UINT8"
945 else:
946 IsArray = True
947 Type = "UINT8"
948
949 if Item and Item['value'].startswith('{'):
950 Type = "UINT8"
951 IsArray = True
952
953 if Struct != '':
954 Type = Struct
955 if Struct in ['UINT8','UINT16','UINT32','UINT64']:
956 IsArray = True
957 Unit = int(Type[4:]) / 8
958 Length = Length / Unit
959 else:
960 IsArray = False
961
962 if IsArray:
963 Name = Name + '[%d]' % Length
964
965 if len(Type) < PosName:
966 Space1 = PosName - len(Type)
967 else:
968 Space1 = 1
969
970 if BsfName != '':
971 NameLine=" - %s\n" % BsfName
972 else:
973 NameLine="\n"
974
975 if Help != '':
976 HelpLine = self.ProcessMultilines (Help, 80)
977
978 if Option != '':
979 OptionLine = self.ProcessMultilines (Option, 80)
980
981 if Offset is None:
982 OffsetStr = '????'
983 else:
984 OffsetStr = '0x%04X' % Offset
985
986 return "\n/** Offset %s%s%s%s**/\n %s%s%s;\n" % (OffsetStr, NameLine, HelpLine, OptionLine, Type, ' ' * Space1, Name,)
987
988 def PostProcessBody (self, TextBody):
989 NewTextBody = []
990 OldTextBody = []
991 IncludeLine = False
992 StructName = ''
993 VariableName = ''
994 IsUpdHdrDefined = False
995 IsUpdHeader = False
996 for Line in TextBody:
997 SplitToLines = Line.splitlines()
998 MatchComment = re.match("^/\*\sCOMMENT:(\w+):([\w|\W|\s]+)\s\*/\s([\s\S]*)", SplitToLines[0])
999 if MatchComment:
1000 if MatchComment.group(1) == 'FSP_UPD_HEADER':
1001 IsUpdHeader = True
1002 else:
1003 IsUpdHeader = False
1004 if IsUpdHdrDefined != True or IsUpdHeader != True:
1005 CommentLine = " " + MatchComment.group(2) + "\n"
1006 NewTextBody.append("/**" + CommentLine + "**/\n")
1007 Line = Line[(len(SplitToLines[0]) + 1):]
1008
1009 Match = re.match("^/\*\sEMBED_STRUCT:(\w+):(\w+):(START|END)\s\*/\s([\s\S]*)", Line)
1010 if Match:
1011 Line = Match.group(4)
1012 if Match.group(1) == 'FSP_UPD_HEADER':
1013 IsUpdHeader = True
1014 else:
1015 IsUpdHeader = False
1016
1017 if Match and Match.group(3) == 'START':
1018 if IsUpdHdrDefined != True or IsUpdHeader != True:
1019 NewTextBody.append ('typedef struct {\n')
1020 StructName = Match.group(1)
1021 VariableName = Match.group(2)
1022 MatchOffset = re.search('/\*\*\sOffset\s0x([a-fA-F0-9]+)', Line)
1023 if MatchOffset:
1024 Offset = int(MatchOffset.group(1), 16)
1025 else:
1026 Offset = None
1027 Line
1028 IncludeLine = True
1029 OldTextBody.append (self.CreateField (None, VariableName, 0, Offset, StructName, '', '', ''))
1030 if IncludeLine:
1031 if IsUpdHdrDefined != True or IsUpdHeader != True:
1032 NewTextBody.append (Line)
1033 else:
1034 OldTextBody.append (Line)
1035
1036 if Match and Match.group(3) == 'END':
1037 if (StructName != Match.group(1)) or (VariableName != Match.group(2)):
1038 print ("Unmatched struct name '%s' and '%s' !" % (StructName, Match.group(1)))
1039 else:
1040 if IsUpdHdrDefined != True or IsUpdHeader != True:
1041 NewTextBody.append ('} %s;\n\n' % StructName)
1042 IsUpdHdrDefined = True
1043 IncludeLine = False
1044 NewTextBody.extend(OldTextBody)
1045 return NewTextBody
1046
1047 def WriteLinesWithoutTailingSpace (self, HeaderFd, Line):
1048 TxtBody2 = Line.splitlines(True)
1049 for Line2 in TxtBody2:
1050 Line2 = Line2.rstrip()
1051 Line2 += '\n'
1052 HeaderFd.write (Line2)
1053 return 0
1054 def CreateHeaderFile (self, InputHeaderFile):
1055 FvDir = self._FvDir
1056
1057 HeaderFileName = 'FspUpd.h'
1058 HeaderFile = os.path.join(FvDir, HeaderFileName)
1059
1060 # Check if header needs to be recreated
1061 if (self.NoDscFileChange (HeaderFile)):
1062 # DSC has not been modified yet
1063 # So don't have to re-generate other files
1064 self.Error = 'No DSC file change, skip to create UPD header file'
1065 return 256
1066
1067 TxtBody = []
1068 for Item in self._CfgItemList:
1069 if str(Item['cname']) == 'Signature' and Item['length'] == 8:
1070 Value = int(Item['value'], 16)
1071 Chars = []
1072 while Value != 0x0:
1073 Chars.append(chr(Value & 0xFF))
1074 Value = Value >> 8
1075 SignatureStr = ''.join(Chars)
1076 # Signature will be _T / _M / _S for FSPT / FSPM / FSPS accordingly
1077 if '_T' in SignatureStr[6:6+2]:
1078 TxtBody.append("#define FSPT_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1079 elif '_M' in SignatureStr[6:6+2]:
1080 TxtBody.append("#define FSPM_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1081 elif '_S' in SignatureStr[6:6+2]:
1082 TxtBody.append("#define FSPS_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1083 TxtBody.append("\n")
1084
1085 for Region in ['UPD']:
1086 UpdOffsetTable = []
1087 UpdSignature = ['0x545F', '0x4D5F', '0x535F'] #['_T', '_M', '_S'] signature for FSPT, FSPM, FSPS
1088 UpdStructure = ['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD']
1089 for Item in self._CfgItemList:
1090 if Item["cname"] == 'Signature' and Item["value"][0:6] in UpdSignature:
1091 UpdOffsetTable.append (Item["offset"])
1092
1093 for UpdIdx in range(len(UpdOffsetTable)):
1094 CommentLine = ""
1095 for Item in self._CfgItemList:
1096 if Item["comment"] != '' and Item["offset"] >= UpdOffsetTable[UpdIdx]:
1097 MatchComment = re.match("^(U|V)PD_DATA_REGION:([\w|\W|\s]+)", Item["comment"])
1098 if MatchComment and MatchComment.group(1) == Region[0]:
1099 CommentLine = " " + MatchComment.group(2) + "\n"
1100 TxtBody.append("/**" + CommentLine + "**/\n")
1101 elif Item["offset"] >= UpdOffsetTable[UpdIdx] and Item["comment"] == '':
1102 Match = re.match("^FSP([\w|\W|\s])_UPD", UpdStructure[UpdIdx])
1103 if Match:
1104 TxtBody.append("/** Fsp " + Match.group(1) + " UPD Configuration\n**/\n")
1105 TxtBody.append("typedef struct {\n")
1106 NextOffset = 0
1107 SpaceIdx = 0
1108 Offset = 0
1109
1110 LastVisible = True
1111 ResvOffset = 0
1112 ResvIdx = 0
1113 LineBuffer = []
1114 InRange = False
1115 for Item in self._CfgItemList:
1116 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == UpdSignature[UpdIdx] or Region[0] == 'V':
1117 InRange = True
1118 if InRange != True:
1119 continue
1120 if Item['cname'] == 'UpdTerminator':
1121 InRange = False
1122
1123 if Item['region'] != Region:
1124 continue
1125
1126 if Item["offset"] < UpdOffsetTable[UpdIdx]:
1127 continue
1128
1129 NextVisible = LastVisible
1130
1131 if LastVisible and (Item['header'] == 'OFF'):
1132 NextVisible = False
1133 ResvOffset = Item['offset']
1134 elif (not LastVisible) and Item['header'] == 'ON':
1135 NextVisible = True
1136 Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx
1137 ResvIdx = ResvIdx + 1
1138 TxtBody.append(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, '', '', '', ''))
1139
1140 if Offset < Item["offset"]:
1141 if LastVisible:
1142 Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx
1143 LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, '', '', '', ''))
1144 SpaceIdx = SpaceIdx + 1
1145 Offset = Item["offset"]
1146
1147 LastVisible = NextVisible
1148
1149 Offset = Offset + Item["length"]
1150 if LastVisible:
1151 for Each in LineBuffer:
1152 TxtBody.append (Each)
1153 LineBuffer = []
1154 Comment = Item["comment"]
1155 Embed = Item["embed"].upper()
1156 if Embed.endswith(':START') or Embed.endswith(':END'):
1157 if not Comment == '' and Embed.endswith(':START'):
1158 Marker = '/* COMMENT:%s */ \n' % Item["comment"]
1159 Marker = Marker + '/* EMBED_STRUCT:%s */ ' % Item["embed"]
1160 else:
1161 Marker = '/* EMBED_STRUCT:%s */ ' % Item["embed"]
1162 else:
1163 if Embed == '':
1164 Marker = ''
1165 else:
1166 self.Error = "Invalid embedded structure format '%s'!\n" % Item["embed"]
1167 return 4
1168 Line = Marker + self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct'], Item['name'], Item['help'], Item['option'])
1169 TxtBody.append(Line)
1170 if Item['cname'] == 'UpdTerminator':
1171 break
1172 TxtBody.append("} " + UpdStructure[UpdIdx] + ";\n\n")
1173
1174 # Handle the embedded data structure
1175 TxtBody = self.PostProcessBody (TxtBody)
1176
1177 HeaderTFileName = 'FsptUpd.h'
1178 HeaderMFileName = 'FspmUpd.h'
1179 HeaderSFileName = 'FspsUpd.h'
1180
1181 UpdRegionCheck = ['FSPT', 'FSPM', 'FSPS'] # FSPX_UPD_REGION
1182 UpdConfigCheck = ['FSP_T', 'FSP_M', 'FSP_S'] # FSP_X_CONFIG, FSP_X_TEST_CONFIG, FSP_X_RESTRICTED_CONFIG
1183 UpdSignatureCheck = ['FSPT_UPD_SIGNATURE', 'FSPM_UPD_SIGNATURE', 'FSPS_UPD_SIGNATURE']
1184 ExcludedSpecificUpd = ['FSPT_ARCH_UPD', 'FSPM_ARCH_UPD', 'FSPS_ARCH_UPD']
1185
1186 IncLines = []
1187 if InputHeaderFile != '':
1188 if not os.path.exists(InputHeaderFile):
1189 self.Error = "Input header file '%s' does not exist" % InputHeaderFile
1190 return 6
1191
1192 InFd = open(InputHeaderFile, "r")
1193 IncLines = InFd.readlines()
1194 InFd.close()
1195
1196 for item in range(len(UpdRegionCheck)):
1197 if UpdRegionCheck[item] == 'FSPT':
1198 HeaderFd = open(os.path.join(FvDir, HeaderTFileName), "w")
1199 FileBase = os.path.basename(os.path.join(FvDir, HeaderTFileName))
1200 elif UpdRegionCheck[item] == 'FSPM':
1201 HeaderFd = open(os.path.join(FvDir, HeaderMFileName), "w")
1202 FileBase = os.path.basename(os.path.join(FvDir, HeaderMFileName))
1203 elif UpdRegionCheck[item] == 'FSPS':
1204 HeaderFd = open(os.path.join(FvDir, HeaderSFileName), "w")
1205 FileBase = os.path.basename(os.path.join(FvDir, HeaderSFileName))
1206 FileName = FileBase.replace(".", "_").upper()
1207 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
1208 HeaderFd.write("#ifndef __%s__\n" % FileName)
1209 HeaderFd.write("#define __%s__\n\n" % FileName)
1210 HeaderFd.write("#include <%s>\n\n" % HeaderFileName)
1211 HeaderFd.write("#pragma pack(1)\n\n")
1212
1213 Export = False
1214 for Line in IncLines:
1215 Match = re.search ("!EXPORT\s+([A-Z]+)\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line)
1216 if Match:
1217 if Match.group(2) == "BEGIN" and Match.group(1) == UpdRegionCheck[item]:
1218 Export = True
1219 continue
1220 else:
1221 Export = False
1222 continue
1223 if Export:
1224 HeaderFd.write(Line)
1225 HeaderFd.write("\n")
1226
1227 Index = 0
1228 StartIndex = 0
1229 EndIndex = 0
1230 StructStart = []
1231 StructStartWithComment = []
1232 StructEnd = []
1233 for Line in TxtBody:
1234 Index += 1
1235 Match = re.match("(typedef struct {)", Line)
1236 if Match:
1237 StartIndex = Index - 1
1238 Match = re.match("}\s([_A-Z0-9]+);", Line)
1239 if Match and (UpdRegionCheck[item] in Match.group(1) or UpdConfigCheck[item] in Match.group(1)) and (ExcludedSpecificUpd[item] not in Match.group(1)):
1240 EndIndex = Index
1241 StructStart.append(StartIndex)
1242 StructEnd.append(EndIndex)
1243 Index = 0
1244 for Line in TxtBody:
1245 Index += 1
1246 for Item in range(len(StructStart)):
1247 if Index == StructStart[Item]:
1248 Match = re.match("^(/\*\*\s*)", Line)
1249 if Match:
1250 StructStartWithComment.append(StructStart[Item])
1251 else:
1252 StructStartWithComment.append(StructStart[Item] + 1)
1253 Index = 0
1254 for Line in TxtBody:
1255 Index += 1
1256 for Item in range(len(StructStart)):
1257 if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]:
1258 self.WriteLinesWithoutTailingSpace(HeaderFd, Line)
1259 HeaderFd.write("#pragma pack()\n\n")
1260 HeaderFd.write("#endif\n")
1261 HeaderFd.close()
1262
1263 HeaderFd = open(HeaderFile, "w")
1264 FileBase = os.path.basename(HeaderFile)
1265 FileName = FileBase.replace(".", "_").upper()
1266 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
1267 HeaderFd.write("#ifndef __%s__\n" % FileName)
1268 HeaderFd.write("#define __%s__\n\n" % FileName)
1269 HeaderFd.write("#include <FspEas.h>\n\n")
1270 HeaderFd.write("#pragma pack(1)\n\n")
1271
1272 for item in range(len(UpdRegionCheck)):
1273 Index = 0
1274 StartIndex = 0
1275 EndIndex = 0
1276 StructStart = []
1277 StructStartWithComment = []
1278 StructEnd = []
1279 for Line in TxtBody:
1280 Index += 1
1281 Match = re.match("(typedef struct {)", Line)
1282 if Match:
1283 StartIndex = Index - 1
1284 Match = re.match("#define\s([_A-Z0-9]+)\s*", Line)
1285 if Match and (UpdSignatureCheck[item] in Match.group(1) or UpdSignatureCheck[item] in Match.group(1)):
1286 StructStart.append(Index - 1)
1287 StructEnd.append(Index)
1288 Index = 0
1289 for Line in TxtBody:
1290 Index += 1
1291 for Item in range(len(StructStart)):
1292 if Index == StructStart[Item]:
1293 Match = re.match("^(/\*\*\s*)", Line)
1294 if Match:
1295 StructStartWithComment.append(StructStart[Item])
1296 else:
1297 StructStartWithComment.append(StructStart[Item] + 1)
1298 Index = 0
1299 for Line in TxtBody:
1300 Index += 1
1301 for Item in range(len(StructStart)):
1302 if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]:
1303 self.WriteLinesWithoutTailingSpace(HeaderFd, Line)
1304 HeaderFd.write("#pragma pack()\n\n")
1305 HeaderFd.write("#endif\n")
1306 HeaderFd.close()
1307
1308 return 0
1309
1310 def WriteBsfStruct (self, BsfFd, Item):
1311 LogExpr = CLogicalExpression()
1312 if Item['type'] == "None":
1313 Space = "gPlatformFspPkgTokenSpaceGuid"
1314 else:
1315 Space = Item['space']
1316 Line = " $%s_%s" % (Space, Item['cname'])
1317 Match = re.match("\s*\{([x0-9a-fA-F,\s]+)\}\s*", Item['value'])
1318 if Match:
1319 DefaultValue = Match.group(1).strip()
1320 else:
1321 DefaultValue = Item['value'].strip()
1322 if 'bitlength' in Item:
1323 BsfFd.write(" %s%s%4d bits $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['bitlength'], DefaultValue))
1324 else:
1325 BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue))
1326 TmpList = []
1327 if Item['type'] == "Combo":
1328 if not Item['option'] in self._BuidinOption:
1329 OptList = Item['option'].split(',')
1330 for Option in OptList:
1331 Option = Option.strip()
1332 (OpVal, OpStr) = Option.split(':')
1333 test = LogExpr.getNumber (OpVal)
1334 if test is None:
1335 raise Exception("Selection Index '%s' is not a number" % OpVal)
1336 TmpList.append((OpVal, OpStr))
1337 return TmpList
1338
1339 def WriteBsfOption (self, BsfFd, Item):
1340 PcdName = Item['space'] + '_' + Item['cname']
1341 WriteHelp = 0
1342 if Item['type'] == "Combo":
1343 if Item['option'] in self._BuidinOption:
1344 Options = self._BuidinOption[Item['option']]
1345 else:
1346 Options = PcdName
1347 BsfFd.write(' %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options))
1348 WriteHelp = 1
1349 elif Item['type'].startswith("EditNum"):
1350 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'])
1351 if Match:
1352 BsfFd.write(' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1)))
1353 WriteHelp = 2
1354 elif Item['type'].startswith("EditText"):
1355 BsfFd.write(' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name']))
1356 WriteHelp = 1
1357 elif Item['type'] == "Table":
1358 Columns = Item['option'].split(',')
1359 if len(Columns) != 0:
1360 BsfFd.write(' %s $%s "%s",' % (Item['type'], PcdName, Item['name']))
1361 for Col in Columns:
1362 Fmt = Col.split(':')
1363 if len(Fmt) != 3:
1364 raise Exception("Column format '%s' is invalid !" % Fmt)
1365 try:
1366 Dtype = int(Fmt[1].strip())
1367 except:
1368 raise Exception("Column size '%s' is invalid !" % Fmt[1])
1369 BsfFd.write('\n Column "%s", %d bytes, %s' % (Fmt[0].strip(), Dtype, Fmt[2].strip()))
1370 BsfFd.write(',\n')
1371 WriteHelp = 1
1372
1373 if WriteHelp > 0:
1374 HelpLines = Item['help'].split('\\n\\r')
1375 FirstLine = True
1376 for HelpLine in HelpLines:
1377 if FirstLine:
1378 FirstLine = False
1379 BsfFd.write(' Help "%s"\n' % (HelpLine))
1380 else:
1381 BsfFd.write(' "%s"\n' % (HelpLine))
1382 if WriteHelp == 2:
1383 BsfFd.write(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3)))
1384
1385 def GenerateBsfFile (self, BsfFile):
1386
1387 if BsfFile == '':
1388 self.Error = "BSF output file '%s' is invalid" % BsfFile
1389 return 1
1390
1391 if (self.NoDscFileChange (BsfFile)):
1392 # DSC has not been modified yet
1393 # So don't have to re-generate other files
1394 self.Error = 'No DSC file change, skip to create UPD BSF file'
1395 return 256
1396
1397 Error = 0
1398 OptionDict = {}
1399 BsfFd = open(BsfFile, "w")
1400 BsfFd.write("%s\n" % (__copyright_bsf__ % date.today().year))
1401 BsfFd.write("%s\n" % self._GlobalDataDef)
1402 BsfFd.write("StructDef\n")
1403 NextOffset = -1
1404 for Item in self._CfgItemList:
1405 if Item['find'] != '':
1406 BsfFd.write('\n Find "%s"\n' % Item['find'])
1407 NextOffset = Item['offset'] + Item['length']
1408 if Item['name'] != '':
1409 if NextOffset != Item['offset']:
1410 BsfFd.write(" Skip %d bytes\n" % (Item['offset'] - NextOffset))
1411 if len(Item['subreg']) > 0:
1412 NextOffset = Item['offset']
1413 BitsOffset = NextOffset * 8
1414 for SubItem in Item['subreg']:
1415 BitsOffset += SubItem['bitlength']
1416 if SubItem['name'] == '':
1417 if 'bitlength' in SubItem:
1418 BsfFd.write(" Skip %d bits\n" % (SubItem['bitlength']))
1419 else:
1420 BsfFd.write(" Skip %d bytes\n" % (SubItem['length']))
1421 else:
1422 Options = self.WriteBsfStruct(BsfFd, SubItem)
1423 if len(Options) > 0:
1424 OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options
1425
1426 NextBitsOffset = (Item['offset'] + Item['length']) * 8
1427 if NextBitsOffset > BitsOffset:
1428 BitsGap = NextBitsOffset - BitsOffset
1429 BitsRemain = BitsGap % 8
1430 if BitsRemain:
1431 BsfFd.write(" Skip %d bits\n" % BitsRemain)
1432 BitsGap -= BitsRemain
1433 BytesRemain = int(BitsGap / 8)
1434 if BytesRemain:
1435 BsfFd.write(" Skip %d bytes\n" % BytesRemain)
1436 NextOffset = Item['offset'] + Item['length']
1437 else:
1438 NextOffset = Item['offset'] + Item['length']
1439 Options = self.WriteBsfStruct(BsfFd, Item)
1440 if len(Options) > 0:
1441 OptionDict[Item['space']+'_'+Item['cname']] = Options
1442 BsfFd.write("\nEndStruct\n\n")
1443
1444 BsfFd.write("%s" % self._BuidinOptionTxt)
1445
1446 for Each in OptionDict:
1447 BsfFd.write("List &%s\n" % Each)
1448 for Item in OptionDict[Each]:
1449 BsfFd.write(' Selection %s , "%s"\n' % (Item[0], Item[1]))
1450 BsfFd.write("EndList\n\n")
1451
1452 BsfFd.write("BeginInfoBlock\n")
1453 BsfFd.write(' PPVer "%s"\n' % (self._CfgBlkDict['ver']))
1454 BsfFd.write(' Description "%s"\n' % (self._CfgBlkDict['name']))
1455 BsfFd.write("EndInfoBlock\n\n")
1456
1457 for Each in self._CfgPageDict:
1458 BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each])
1459 BsfItems = []
1460 for Item in self._CfgItemList:
1461 if Item['name'] != '':
1462 if Item['page'] != Each:
1463 continue
1464 if len(Item['subreg']) > 0:
1465 for SubItem in Item['subreg']:
1466 if SubItem['name'] != '':
1467 BsfItems.append(SubItem)
1468 else:
1469 BsfItems.append(Item)
1470
1471 BsfItems.sort(key=lambda x: x['order'])
1472
1473 for Item in BsfItems:
1474 self.WriteBsfOption (BsfFd, Item)
1475 BsfFd.write("EndPage\n\n")
1476
1477 BsfFd.close()
1478 return Error
1479
1480
1481 def Usage():
1482 print ("GenCfgOpt Version 0.56")
1483 print ("Usage:")
1484 print (" GenCfgOpt UPDTXT PlatformDscFile BuildFvDir [-D Macros]")
1485 print (" GenCfgOpt HEADER PlatformDscFile BuildFvDir InputHFile [-D Macros]")
1486 print (" GenCfgOpt GENBSF PlatformDscFile BuildFvDir BsfOutFile [-D Macros]")
1487
1488 def Main():
1489 #
1490 # Parse the options and args
1491 #
1492 i = 1
1493
1494 GenCfgOpt = CGenCfgOpt()
1495 while i < len(sys.argv):
1496 if sys.argv[i].strip().lower() == "--pcd":
1497 BuildOptionPcd.append(sys.argv[i+1])
1498 i += 1
1499 i += 1
1500 argc = len(sys.argv)
1501 if argc < 4:
1502 Usage()
1503 return 1
1504 else:
1505 DscFile = sys.argv[2]
1506 if not os.path.exists(DscFile):
1507 print ("ERROR: Cannot open DSC file '%s' !" % DscFile)
1508 return 2
1509
1510 OutFile = ''
1511 if argc > 4:
1512 if sys.argv[4][0] == '-':
1513 Start = 4
1514 else:
1515 OutFile = sys.argv[4]
1516 Start = 5
1517 if argc > Start:
1518 if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:
1519 print ("ERROR: Macro parsing failed !")
1520 return 3
1521
1522 FvDir = sys.argv[3]
1523 if not os.path.exists(FvDir):
1524 os.makedirs(FvDir)
1525
1526 if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:
1527 print ("ERROR: %s !" % GenCfgOpt.Error)
1528 return 5
1529
1530 if GenCfgOpt.UpdateSubRegionDefaultValue() != 0:
1531 print ("ERROR: %s !" % GenCfgOpt.Error)
1532 return 7
1533
1534 if sys.argv[1] == "UPDTXT":
1535 Ret = GenCfgOpt.CreateSplitUpdTxt(OutFile)
1536 if Ret != 0:
1537 # No change is detected
1538 if Ret == 256:
1539 print ("INFO: %s !" % (GenCfgOpt.Error))
1540 else :
1541 print ("ERROR: %s !" % (GenCfgOpt.Error))
1542 return Ret
1543 elif sys.argv[1] == "HEADER":
1544 Ret = GenCfgOpt.CreateHeaderFile(OutFile)
1545 if Ret != 0:
1546 # No change is detected
1547 if Ret == 256:
1548 print ("INFO: %s !" % (GenCfgOpt.Error))
1549 else :
1550 print ("ERROR: %s !" % (GenCfgOpt.Error))
1551 return 8
1552 return Ret
1553 elif sys.argv[1] == "GENBSF":
1554 Ret = GenCfgOpt.GenerateBsfFile(OutFile)
1555 if Ret != 0:
1556 # No change is detected
1557 if Ret == 256:
1558 print ("INFO: %s !" % (GenCfgOpt.Error))
1559 else :
1560 print ("ERROR: %s !" % (GenCfgOpt.Error))
1561 return 9
1562 return Ret
1563 else:
1564 if argc < 5:
1565 Usage()
1566 return 1
1567 print ("ERROR: Unknown command '%s' !" % sys.argv[1])
1568 Usage()
1569 return 1
1570 return 0
1571 return 0
1572
1573
1574 if __name__ == '__main__':
1575 sys.exit(Main())