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