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