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