]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFsp2Pkg/Tools/GenCfgOpt.py
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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)] = Match.group(2)
552 if self.Debug:
553 print ("INFO : DEFINE %s = [ %s ]" % (Match.group(1), 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 CreateSplitUpdTxt (self, UpdTxtFile):
814 GuidList = ['FSP_T_UPD_TOOL_GUID','FSP_M_UPD_TOOL_GUID','FSP_S_UPD_TOOL_GUID']
815 SignatureList = ['0x545F', '0x4D5F','0x535F'] # _T, _M, and _S signature for FSPT, FSPM, FSPS
816 for Index in range(len(GuidList)):
817 UpdTxtFile = ''
818 FvDir = self._FvDir
819 if GuidList[Index] not in self._MacroDict:
820 self.Error = "%s definition is missing in DSC file" % (GuidList[Index])
821 return 1
822
823 if UpdTxtFile == '':
824 UpdTxtFile = os.path.join(FvDir, self._MacroDict[GuidList[Index]] + '.txt')
825
826 ReCreate = False
827 if not os.path.exists(UpdTxtFile):
828 ReCreate = True
829 else:
830 DscTime = os.path.getmtime(self._DscFile)
831 TxtTime = os.path.getmtime(UpdTxtFile)
832 if DscTime > TxtTime:
833 ReCreate = True
834
835 if not ReCreate:
836 # DSC has not been modified yet
837 # So don't have to re-generate other files
838 self.Error = 'No DSC file change, skip to create UPD TXT file'
839 return 256
840
841 TxtFd = open(UpdTxtFile, "w")
842 TxtFd.write("%s\n" % (__copyright_txt__ % date.today().year))
843
844 NextOffset = 0
845 SpaceIdx = 0
846 StartAddr = 0
847 EndAddr = 0
848 Default = 'DEFAULT|'
849 InRange = False
850 for Item in self._CfgItemList:
851 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == SignatureList[Index]:
852 StartAddr = Item['offset']
853 NextOffset = StartAddr
854 InRange = True
855 if Item['cname'] == 'UpdTerminator' and InRange == True:
856 EndAddr = Item['offset']
857 InRange = False
858 InRange = False
859 for Item in self._CfgItemList:
860 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == SignatureList[Index]:
861 InRange = True
862 if InRange != True:
863 continue
864 if Item['cname'] == 'UpdTerminator':
865 InRange = False
866 if Item['region'] != 'UPD':
867 continue
868 Offset = Item['offset']
869 if StartAddr > Offset or EndAddr < Offset:
870 continue
871 if NextOffset < Offset:
872 # insert one line
873 TxtFd.write("%s.UnusedUpdSpace%d|%s0x%04X|0x%04X|{0}\n" % (Item['space'], SpaceIdx, Default, NextOffset - StartAddr, Offset - NextOffset))
874 SpaceIdx = SpaceIdx + 1
875 NextOffset = Offset + Item['length']
876 TxtFd.write("%s.%s|%s0x%04X|%s|%s\n" % (Item['space'],Item['cname'],Default,Item['offset'] - StartAddr,Item['length'],Item['value']))
877 TxtFd.close()
878 return 0
879
880 def ProcessMultilines (self, String, MaxCharLength):
881 Multilines = ''
882 StringLength = len(String)
883 CurrentStringStart = 0
884 StringOffset = 0
885 BreakLineDict = []
886 if len(String) <= MaxCharLength:
887 while (StringOffset < StringLength):
888 if StringOffset >= 1:
889 if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
890 BreakLineDict.append (StringOffset + 1)
891 StringOffset += 1
892 if BreakLineDict != []:
893 for Each in BreakLineDict:
894 Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip()
895 CurrentStringStart = Each
896 if StringLength - CurrentStringStart > 0:
897 Multilines += " %s\n" % String[CurrentStringStart:].lstrip()
898 else:
899 Multilines = " %s\n" % String
900 else:
901 NewLineStart = 0
902 NewLineCount = 0
903 FoundSpaceChar = False
904 while (StringOffset < StringLength):
905 if StringOffset >= 1:
906 if NewLineCount >= MaxCharLength - 1:
907 if String[StringOffset] == ' ' and StringLength - StringOffset > 10:
908 BreakLineDict.append (NewLineStart + NewLineCount)
909 NewLineStart = NewLineStart + NewLineCount
910 NewLineCount = 0
911 FoundSpaceChar = True
912 elif StringOffset == StringLength - 1 and FoundSpaceChar == False:
913 BreakLineDict.append (0)
914 if String[StringOffset - 1] == '\\' and String[StringOffset] == 'n':
915 BreakLineDict.append (StringOffset + 1)
916 NewLineStart = StringOffset + 1
917 NewLineCount = 0
918 StringOffset += 1
919 NewLineCount += 1
920 if BreakLineDict != []:
921 BreakLineDict.sort ()
922 for Each in BreakLineDict:
923 if Each > 0:
924 Multilines += " %s\n" % String[CurrentStringStart:Each].lstrip()
925 CurrentStringStart = Each
926 if StringLength - CurrentStringStart > 0:
927 Multilines += " %s\n" % String[CurrentStringStart:].lstrip()
928 return Multilines
929
930 def CreateField (self, Item, Name, Length, Offset, Struct, BsfName, Help, Option):
931 PosName = 28
932 PosComment = 30
933 NameLine=''
934 HelpLine=''
935 OptionLine=''
936
937 IsArray = False
938 if Length in [1,2,4,8]:
939 Type = "UINT%d" % (Length * 8)
940 if Name.startswith("UnusedUpdSpace") and Length != 1:
941 IsArray = True
942 Type = "UINT8"
943 else:
944 IsArray = True
945 Type = "UINT8"
946
947 if Item and Item['value'].startswith('{'):
948 Type = "UINT8"
949 IsArray = True
950
951 if Struct != '':
952 Type = Struct
953 if Struct in ['UINT8','UINT16','UINT32','UINT64']:
954 IsArray = True
955 Unit = int(Type[4:]) / 8
956 Length = Length / Unit
957 else:
958 IsArray = False
959
960 if IsArray:
961 Name = Name + '[%d]' % Length
962
963 if len(Type) < PosName:
964 Space1 = PosName - len(Type)
965 else:
966 Space1 = 1
967
968 if BsfName != '':
969 NameLine=" - %s\n" % BsfName
970 else:
971 NameLine="\n"
972
973 if Help != '':
974 HelpLine = self.ProcessMultilines (Help, 80)
975
976 if Option != '':
977 OptionLine = self.ProcessMultilines (Option, 80)
978
979 if Offset is None:
980 OffsetStr = '????'
981 else:
982 OffsetStr = '0x%04X' % Offset
983
984 return "\n/** Offset %s%s%s%s**/\n %s%s%s;\n" % (OffsetStr, NameLine, HelpLine, OptionLine, Type, ' ' * Space1, Name,)
985
986 def PostProcessBody (self, TextBody):
987 NewTextBody = []
988 OldTextBody = []
989 IncludeLine = False
990 StructName = ''
991 VariableName = ''
992 IsUpdHdrDefined = False
993 IsUpdHeader = False
994 for Line in TextBody:
995 SplitToLines = Line.splitlines()
996 MatchComment = re.match("^/\*\sCOMMENT:(\w+):([\w|\W|\s]+)\s\*/\s([\s\S]*)", SplitToLines[0])
997 if MatchComment:
998 if MatchComment.group(1) == 'FSP_UPD_HEADER':
999 IsUpdHeader = True
1000 else:
1001 IsUpdHeader = False
1002 if IsUpdHdrDefined != True or IsUpdHeader != True:
1003 CommentLine = " " + MatchComment.group(2) + "\n"
1004 NewTextBody.append("/**" + CommentLine + "**/\n")
1005 Line = Line[(len(SplitToLines[0]) + 1):]
1006
1007 Match = re.match("^/\*\sEMBED_STRUCT:(\w+):(\w+):(START|END)\s\*/\s([\s\S]*)", Line)
1008 if Match:
1009 Line = Match.group(4)
1010 if Match.group(1) == 'FSP_UPD_HEADER':
1011 IsUpdHeader = True
1012 else:
1013 IsUpdHeader = False
1014
1015 if Match and Match.group(3) == 'START':
1016 if IsUpdHdrDefined != True or IsUpdHeader != True:
1017 NewTextBody.append ('typedef struct {\n')
1018 StructName = Match.group(1)
1019 VariableName = Match.group(2)
1020 MatchOffset = re.search('/\*\*\sOffset\s0x([a-fA-F0-9]+)', Line)
1021 if MatchOffset:
1022 Offset = int(MatchOffset.group(1), 16)
1023 else:
1024 Offset = None
1025 Line
1026 IncludeLine = True
1027 OldTextBody.append (self.CreateField (None, VariableName, 0, Offset, StructName, '', '', ''))
1028 if IncludeLine:
1029 if IsUpdHdrDefined != True or IsUpdHeader != True:
1030 NewTextBody.append (Line)
1031 else:
1032 OldTextBody.append (Line)
1033
1034 if Match and Match.group(3) == 'END':
1035 if (StructName != Match.group(1)) or (VariableName != Match.group(2)):
1036 print ("Unmatched struct name '%s' and '%s' !" % (StructName, Match.group(1)))
1037 else:
1038 if IsUpdHdrDefined != True or IsUpdHeader != True:
1039 NewTextBody.append ('} %s;\n\n' % StructName)
1040 IsUpdHdrDefined = True
1041 IncludeLine = False
1042 NewTextBody.extend(OldTextBody)
1043 return NewTextBody
1044
1045 def WriteLinesWithoutTailingSpace (self, HeaderFd, Line):
1046 TxtBody2 = Line.splitlines(True)
1047 for Line2 in TxtBody2:
1048 Line2 = Line2.rstrip()
1049 Line2 += '\n'
1050 HeaderFd.write (Line2)
1051 return 0
1052 def CreateHeaderFile (self, InputHeaderFile):
1053 FvDir = self._FvDir
1054
1055 HeaderFileName = 'FspUpd.h'
1056 HeaderFile = os.path.join(FvDir, HeaderFileName)
1057
1058 # Check if header needs to be recreated
1059 ReCreate = False
1060
1061 TxtBody = []
1062 for Item in self._CfgItemList:
1063 if str(Item['cname']) == 'Signature' and Item['length'] == 8:
1064 Value = int(Item['value'], 16)
1065 Chars = []
1066 while Value != 0x0:
1067 Chars.append(chr(Value & 0xFF))
1068 Value = Value >> 8
1069 SignatureStr = ''.join(Chars)
1070 # Signature will be _T / _M / _S for FSPT / FSPM / FSPS accordingly
1071 if '_T' in SignatureStr[6:6+2]:
1072 TxtBody.append("#define FSPT_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1073 elif '_M' in SignatureStr[6:6+2]:
1074 TxtBody.append("#define FSPM_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1075 elif '_S' in SignatureStr[6:6+2]:
1076 TxtBody.append("#define FSPS_UPD_SIGNATURE %s /* '%s' */\n\n" % (Item['value'], SignatureStr))
1077 TxtBody.append("\n")
1078
1079 for Region in ['UPD']:
1080 UpdOffsetTable = []
1081 UpdSignature = ['0x545F', '0x4D5F', '0x535F'] #['_T', '_M', '_S'] signature for FSPT, FSPM, FSPS
1082 UpdStructure = ['FSPT_UPD', 'FSPM_UPD', 'FSPS_UPD']
1083 for Item in self._CfgItemList:
1084 if Item["cname"] == 'Signature' and Item["value"][0:6] in UpdSignature:
1085 UpdOffsetTable.append (Item["offset"])
1086
1087 for UpdIdx in range(len(UpdOffsetTable)):
1088 CommentLine = ""
1089 for Item in self._CfgItemList:
1090 if Item["comment"] != '' and Item["offset"] >= UpdOffsetTable[UpdIdx]:
1091 MatchComment = re.match("^(U|V)PD_DATA_REGION:([\w|\W|\s]+)", Item["comment"])
1092 if MatchComment and MatchComment.group(1) == Region[0]:
1093 CommentLine = " " + MatchComment.group(2) + "\n"
1094 TxtBody.append("/**" + CommentLine + "**/\n")
1095 elif Item["offset"] >= UpdOffsetTable[UpdIdx] and Item["comment"] == '':
1096 Match = re.match("^FSP([\w|\W|\s])_UPD", UpdStructure[UpdIdx])
1097 if Match:
1098 TxtBody.append("/** Fsp " + Match.group(1) + " UPD Configuration\n**/\n")
1099 TxtBody.append("typedef struct {\n")
1100 NextOffset = 0
1101 SpaceIdx = 0
1102 Offset = 0
1103
1104 LastVisible = True
1105 ResvOffset = 0
1106 ResvIdx = 0
1107 LineBuffer = []
1108 InRange = False
1109 for Item in self._CfgItemList:
1110 if Item['cname'] == 'Signature' and str(Item['value'])[0:6] == UpdSignature[UpdIdx] or Region[0] == 'V':
1111 InRange = True
1112 if InRange != True:
1113 continue
1114 if Item['cname'] == 'UpdTerminator':
1115 InRange = False
1116
1117 if Item['region'] != Region:
1118 continue
1119
1120 if Item["offset"] < UpdOffsetTable[UpdIdx]:
1121 continue
1122
1123 NextVisible = LastVisible
1124
1125 if LastVisible and (Item['header'] == 'OFF'):
1126 NextVisible = False
1127 ResvOffset = Item['offset']
1128 elif (not LastVisible) and Item['header'] == 'ON':
1129 NextVisible = True
1130 Name = "Reserved" + Region[0] + "pdSpace%d" % ResvIdx
1131 ResvIdx = ResvIdx + 1
1132 TxtBody.append(self.CreateField (Item, Name, Item["offset"] - ResvOffset, ResvOffset, '', '', '', ''))
1133
1134 if Offset < Item["offset"]:
1135 if LastVisible:
1136 Name = "Unused" + Region[0] + "pdSpace%d" % SpaceIdx
1137 LineBuffer.append(self.CreateField (Item, Name, Item["offset"] - Offset, Offset, '', '', '', ''))
1138 SpaceIdx = SpaceIdx + 1
1139 Offset = Item["offset"]
1140
1141 LastVisible = NextVisible
1142
1143 Offset = Offset + Item["length"]
1144 if LastVisible:
1145 for Each in LineBuffer:
1146 TxtBody.append (Each)
1147 LineBuffer = []
1148 Comment = Item["comment"]
1149 Embed = Item["embed"].upper()
1150 if Embed.endswith(':START') or Embed.endswith(':END'):
1151 if not Comment == '' and Embed.endswith(':START'):
1152 Marker = '/* COMMENT:%s */ \n' % Item["comment"]
1153 Marker = Marker + '/* EMBED_STRUCT:%s */ ' % Item["embed"]
1154 else:
1155 Marker = '/* EMBED_STRUCT:%s */ ' % Item["embed"]
1156 else:
1157 if Embed == '':
1158 Marker = ''
1159 else:
1160 self.Error = "Invalid embedded structure format '%s'!\n" % Item["embed"]
1161 return 4
1162 Line = Marker + self.CreateField (Item, Item["cname"], Item["length"], Item["offset"], Item['struct'], Item['name'], Item['help'], Item['option'])
1163 TxtBody.append(Line)
1164 if Item['cname'] == 'UpdTerminator':
1165 break
1166 TxtBody.append("} " + UpdStructure[UpdIdx] + ";\n\n")
1167
1168 # Handle the embedded data structure
1169 TxtBody = self.PostProcessBody (TxtBody)
1170
1171 HeaderTFileName = 'FsptUpd.h'
1172 HeaderMFileName = 'FspmUpd.h'
1173 HeaderSFileName = 'FspsUpd.h'
1174
1175 UpdRegionCheck = ['FSPT', 'FSPM', 'FSPS'] # FSPX_UPD_REGION
1176 UpdConfigCheck = ['FSP_T', 'FSP_M', 'FSP_S'] # FSP_X_CONFIG, FSP_X_TEST_CONFIG, FSP_X_RESTRICTED_CONFIG
1177 UpdSignatureCheck = ['FSPT_UPD_SIGNATURE', 'FSPM_UPD_SIGNATURE', 'FSPS_UPD_SIGNATURE']
1178 ExcludedSpecificUpd = 'FSPM_ARCH_UPD'
1179
1180 if InputHeaderFile != '':
1181 if not os.path.exists(InputHeaderFile):
1182 self.Error = "Input header file '%s' does not exist" % InputHeaderFile
1183 return 6
1184
1185 InFd = open(InputHeaderFile, "r")
1186 IncLines = InFd.readlines()
1187 InFd.close()
1188
1189 for item in range(len(UpdRegionCheck)):
1190 if UpdRegionCheck[item] == 'FSPT':
1191 HeaderFd = open(os.path.join(FvDir, HeaderTFileName), "w")
1192 FileBase = os.path.basename(os.path.join(FvDir, HeaderTFileName))
1193 elif UpdRegionCheck[item] == 'FSPM':
1194 HeaderFd = open(os.path.join(FvDir, HeaderMFileName), "w")
1195 FileBase = os.path.basename(os.path.join(FvDir, HeaderMFileName))
1196 elif UpdRegionCheck[item] == 'FSPS':
1197 HeaderFd = open(os.path.join(FvDir, HeaderSFileName), "w")
1198 FileBase = os.path.basename(os.path.join(FvDir, HeaderSFileName))
1199 FileName = FileBase.replace(".", "_").upper()
1200 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
1201 HeaderFd.write("#ifndef __%s__\n" % FileName)
1202 HeaderFd.write("#define __%s__\n\n" % FileName)
1203 HeaderFd.write("#include <%s>\n\n" % HeaderFileName)
1204 HeaderFd.write("#pragma pack(1)\n\n")
1205
1206 Export = False
1207 for Line in IncLines:
1208 Match = re.search ("!EXPORT\s+([A-Z]+)\s+EXTERNAL_BOOTLOADER_STRUCT_(BEGIN|END)\s+", Line)
1209 if Match:
1210 if Match.group(2) == "BEGIN" and Match.group(1) == UpdRegionCheck[item]:
1211 Export = True
1212 continue
1213 else:
1214 Export = False
1215 continue
1216 if Export:
1217 HeaderFd.write(Line)
1218 HeaderFd.write("\n")
1219
1220 Index = 0
1221 StartIndex = 0
1222 EndIndex = 0
1223 StructStart = []
1224 StructStartWithComment = []
1225 StructEnd = []
1226 for Line in TxtBody:
1227 Index += 1
1228 Match = re.match("(typedef struct {)", Line)
1229 if Match:
1230 StartIndex = Index - 1
1231 Match = re.match("}\s([_A-Z0-9]+);", Line)
1232 if Match and (UpdRegionCheck[item] in Match.group(1) or UpdConfigCheck[item] in Match.group(1)) and (ExcludedSpecificUpd not in Match.group(1)):
1233 EndIndex = Index
1234 StructStart.append(StartIndex)
1235 StructEnd.append(EndIndex)
1236 Index = 0
1237 for Line in TxtBody:
1238 Index += 1
1239 for Item in range(len(StructStart)):
1240 if Index == StructStart[Item]:
1241 Match = re.match("^(/\*\*\s*)", Line)
1242 if Match:
1243 StructStartWithComment.append(StructStart[Item])
1244 else:
1245 StructStartWithComment.append(StructStart[Item] + 1)
1246 Index = 0
1247 for Line in TxtBody:
1248 Index += 1
1249 for Item in range(len(StructStart)):
1250 if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]:
1251 self.WriteLinesWithoutTailingSpace(HeaderFd, Line)
1252 HeaderFd.write("#pragma pack()\n\n")
1253 HeaderFd.write("#endif\n")
1254 HeaderFd.close()
1255
1256 HeaderFd = open(HeaderFile, "w")
1257 FileBase = os.path.basename(HeaderFile)
1258 FileName = FileBase.replace(".", "_").upper()
1259 HeaderFd.write("%s\n" % (__copyright_h__ % date.today().year))
1260 HeaderFd.write("#ifndef __%s__\n" % FileName)
1261 HeaderFd.write("#define __%s__\n\n" % FileName)
1262 HeaderFd.write("#include <FspEas.h>\n\n")
1263 HeaderFd.write("#pragma pack(1)\n\n")
1264
1265 for item in range(len(UpdRegionCheck)):
1266 Index = 0
1267 StartIndex = 0
1268 EndIndex = 0
1269 StructStart = []
1270 StructStartWithComment = []
1271 StructEnd = []
1272 for Line in TxtBody:
1273 Index += 1
1274 Match = re.match("(typedef struct {)", Line)
1275 if Match:
1276 StartIndex = Index - 1
1277 Match = re.match("#define\s([_A-Z0-9]+)\s*", Line)
1278 if Match and (UpdSignatureCheck[item] in Match.group(1) or UpdSignatureCheck[item] in Match.group(1)):
1279 StructStart.append(Index - 1)
1280 StructEnd.append(Index)
1281 Index = 0
1282 for Line in TxtBody:
1283 Index += 1
1284 for Item in range(len(StructStart)):
1285 if Index == StructStart[Item]:
1286 Match = re.match("^(/\*\*\s*)", Line)
1287 if Match:
1288 StructStartWithComment.append(StructStart[Item])
1289 else:
1290 StructStartWithComment.append(StructStart[Item] + 1)
1291 Index = 0
1292 for Line in TxtBody:
1293 Index += 1
1294 for Item in range(len(StructStart)):
1295 if Index >= StructStartWithComment[Item] and Index <= StructEnd[Item]:
1296 self.WriteLinesWithoutTailingSpace(HeaderFd, Line)
1297 HeaderFd.write("#pragma pack()\n\n")
1298 HeaderFd.write("#endif\n")
1299 HeaderFd.close()
1300
1301 return 0
1302
1303 def WriteBsfStruct (self, BsfFd, Item):
1304 LogExpr = CLogicalExpression()
1305 if Item['type'] == "None":
1306 Space = "gPlatformFspPkgTokenSpaceGuid"
1307 else:
1308 Space = Item['space']
1309 Line = " $%s_%s" % (Space, Item['cname'])
1310 Match = re.match("\s*\{([x0-9a-fA-F,\s]+)\}\s*", Item['value'])
1311 if Match:
1312 DefaultValue = Match.group(1).strip()
1313 else:
1314 DefaultValue = Item['value'].strip()
1315 if 'bitlength' in Item:
1316 BsfFd.write(" %s%s%4d bits $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['bitlength'], DefaultValue))
1317 else:
1318 BsfFd.write(" %s%s%4d bytes $_DEFAULT_ = %s\n" % (Line, ' ' * (64 - len(Line)), Item['length'], DefaultValue))
1319 TmpList = []
1320 if Item['type'] == "Combo":
1321 if not Item['option'] in self._BuidinOption:
1322 OptList = Item['option'].split(',')
1323 for Option in OptList:
1324 Option = Option.strip()
1325 (OpVal, OpStr) = Option.split(':')
1326 test = LogExpr.getNumber (OpVal)
1327 if test is None:
1328 raise Exception("Selection Index '%s' is not a number" % OpVal)
1329 TmpList.append((OpVal, OpStr))
1330 return TmpList
1331
1332 def WriteBsfOption (self, BsfFd, Item):
1333 PcdName = Item['space'] + '_' + Item['cname']
1334 WriteHelp = 0
1335 if Item['type'] == "Combo":
1336 if Item['option'] in self._BuidinOption:
1337 Options = self._BuidinOption[Item['option']]
1338 else:
1339 Options = PcdName
1340 BsfFd.write(' %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options))
1341 WriteHelp = 1
1342 elif Item['type'].startswith("EditNum"):
1343 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'])
1344 if Match:
1345 BsfFd.write(' EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1)))
1346 WriteHelp = 2
1347 elif Item['type'].startswith("EditText"):
1348 BsfFd.write(' %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name']))
1349 WriteHelp = 1
1350 elif Item['type'] == "Table":
1351 Columns = Item['option'].split(',')
1352 if len(Columns) != 0:
1353 BsfFd.write(' %s $%s "%s",' % (Item['type'], PcdName, Item['name']))
1354 for Col in Columns:
1355 Fmt = Col.split(':')
1356 if len(Fmt) != 3:
1357 raise Exception("Column format '%s' is invalid !" % Fmt)
1358 try:
1359 Dtype = int(Fmt[1].strip())
1360 except:
1361 raise Exception("Column size '%s' is invalid !" % Fmt[1])
1362 BsfFd.write('\n Column "%s", %d bytes, %s' % (Fmt[0].strip(), Dtype, Fmt[2].strip()))
1363 BsfFd.write(',\n')
1364 WriteHelp = 1
1365
1366 if WriteHelp > 0:
1367 HelpLines = Item['help'].split('\\n\\r')
1368 FirstLine = True
1369 for HelpLine in HelpLines:
1370 if FirstLine:
1371 FirstLine = False
1372 BsfFd.write(' Help "%s"\n' % (HelpLine))
1373 else:
1374 BsfFd.write(' "%s"\n' % (HelpLine))
1375 if WriteHelp == 2:
1376 BsfFd.write(' "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3)))
1377
1378 def GenerateBsfFile (self, BsfFile):
1379
1380 if BsfFile == '':
1381 self.Error = "BSF output file '%s' is invalid" % BsfFile
1382 return 1
1383
1384 Error = 0
1385 OptionDict = {}
1386 BsfFd = open(BsfFile, "w")
1387 BsfFd.write("%s\n" % (__copyright_bsf__ % date.today().year))
1388 BsfFd.write("%s\n" % self._GlobalDataDef)
1389 BsfFd.write("StructDef\n")
1390 NextOffset = -1
1391 for Item in self._CfgItemList:
1392 if Item['find'] != '':
1393 BsfFd.write('\n Find "%s"\n' % Item['find'])
1394 NextOffset = Item['offset'] + Item['length']
1395 if Item['name'] != '':
1396 if NextOffset != Item['offset']:
1397 BsfFd.write(" Skip %d bytes\n" % (Item['offset'] - NextOffset))
1398 if len(Item['subreg']) > 0:
1399 NextOffset = Item['offset']
1400 BitsOffset = NextOffset * 8
1401 for SubItem in Item['subreg']:
1402 BitsOffset += SubItem['bitlength']
1403 if SubItem['name'] == '':
1404 if 'bitlength' in SubItem:
1405 BsfFd.write(" Skip %d bits\n" % (SubItem['bitlength']))
1406 else:
1407 BsfFd.write(" Skip %d bytes\n" % (SubItem['length']))
1408 else:
1409 Options = self.WriteBsfStruct(BsfFd, SubItem)
1410 if len(Options) > 0:
1411 OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options
1412
1413 NextBitsOffset = (Item['offset'] + Item['length']) * 8
1414 if NextBitsOffset > BitsOffset:
1415 BitsGap = NextBitsOffset - BitsOffset
1416 BitsRemain = BitsGap % 8
1417 if BitsRemain:
1418 BsfFd.write(" Skip %d bits\n" % BitsRemain)
1419 BitsGap -= BitsRemain
1420 BytesRemain = int(BitsGap / 8)
1421 if BytesRemain:
1422 BsfFd.write(" Skip %d bytes\n" % BytesRemain)
1423 NextOffset = Item['offset'] + Item['length']
1424 else:
1425 NextOffset = Item['offset'] + Item['length']
1426 Options = self.WriteBsfStruct(BsfFd, Item)
1427 if len(Options) > 0:
1428 OptionDict[Item['space']+'_'+Item['cname']] = Options
1429 BsfFd.write("\nEndStruct\n\n")
1430
1431 BsfFd.write("%s" % self._BuidinOptionTxt)
1432
1433 for Each in OptionDict:
1434 BsfFd.write("List &%s\n" % Each)
1435 for Item in OptionDict[Each]:
1436 BsfFd.write(' Selection %s , "%s"\n' % (Item[0], Item[1]))
1437 BsfFd.write("EndList\n\n")
1438
1439 BsfFd.write("BeginInfoBlock\n")
1440 BsfFd.write(' PPVer "%s"\n' % (self._CfgBlkDict['ver']))
1441 BsfFd.write(' Description "%s"\n' % (self._CfgBlkDict['name']))
1442 BsfFd.write("EndInfoBlock\n\n")
1443
1444 for Each in self._CfgPageDict:
1445 BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each])
1446 BsfItems = []
1447 for Item in self._CfgItemList:
1448 if Item['name'] != '':
1449 if Item['page'] != Each:
1450 continue
1451 if len(Item['subreg']) > 0:
1452 for SubItem in Item['subreg']:
1453 if SubItem['name'] != '':
1454 BsfItems.append(SubItem)
1455 else:
1456 BsfItems.append(Item)
1457
1458 BsfItems.sort(key=lambda x: x['order'])
1459
1460 for Item in BsfItems:
1461 self.WriteBsfOption (BsfFd, Item)
1462 BsfFd.write("EndPage\n\n")
1463
1464 BsfFd.close()
1465 return Error
1466
1467
1468 def Usage():
1469 print ("GenCfgOpt Version 0.54")
1470 print ("Usage:")
1471 print (" GenCfgOpt UPDTXT PlatformDscFile BuildFvDir [-D Macros]")
1472 print (" GenCfgOpt HEADER PlatformDscFile BuildFvDir InputHFile [-D Macros]")
1473 print (" GenCfgOpt GENBSF PlatformDscFile BuildFvDir BsfOutFile [-D Macros]")
1474
1475 def Main():
1476 #
1477 # Parse the options and args
1478 #
1479 i = 1
1480
1481 GenCfgOpt = CGenCfgOpt()
1482 while i < len(sys.argv):
1483 if sys.argv[i].strip().lower() == "--pcd":
1484 BuildOptionPcd.append(sys.argv[i+1])
1485 i += 1
1486 i += 1
1487 argc = len(sys.argv)
1488 if argc < 4:
1489 Usage()
1490 return 1
1491 else:
1492 DscFile = sys.argv[2]
1493 if not os.path.exists(DscFile):
1494 print ("ERROR: Cannot open DSC file '%s' !" % DscFile)
1495 return 2
1496
1497 OutFile = ''
1498 if argc > 4:
1499 if sys.argv[4][0] == '-':
1500 Start = 4
1501 else:
1502 OutFile = sys.argv[4]
1503 Start = 5
1504 if argc > Start:
1505 if GenCfgOpt.ParseMacros(sys.argv[Start:]) != 0:
1506 print ("ERROR: Macro parsing failed !")
1507 return 3
1508
1509 FvDir = sys.argv[3]
1510 if not os.path.exists(FvDir):
1511 os.makedirs(FvDir)
1512
1513 if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:
1514 print ("ERROR: %s !" % GenCfgOpt.Error)
1515 return 5
1516
1517 if GenCfgOpt.UpdateSubRegionDefaultValue() != 0:
1518 print ("ERROR: %s !" % GenCfgOpt.Error)
1519 return 7
1520
1521 if sys.argv[1] == "UPDTXT":
1522 Ret = GenCfgOpt.CreateSplitUpdTxt(OutFile)
1523 if Ret != 0:
1524 # No change is detected
1525 if Ret == 256:
1526 print ("INFO: %s !" % (GenCfgOpt.Error))
1527 else :
1528 print ("ERROR: %s !" % (GenCfgOpt.Error))
1529 return Ret
1530 elif sys.argv[1] == "HEADER":
1531 if GenCfgOpt.CreateHeaderFile(OutFile) != 0:
1532 print ("ERROR: %s !" % GenCfgOpt.Error)
1533 return 8
1534 elif sys.argv[1] == "GENBSF":
1535 if GenCfgOpt.GenerateBsfFile(OutFile) != 0:
1536 print ("ERROR: %s !" % GenCfgOpt.Error)
1537 return 9
1538 else:
1539 if argc < 5:
1540 Usage()
1541 return 1
1542 print ("ERROR: Unknown command '%s' !" % sys.argv[1])
1543 Usage()
1544 return 1
1545 return 0
1546 return 0
1547
1548
1549 if __name__ == '__main__':
1550 sys.exit(Main())