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