IntelFsp2Pkg/GenCfgOpt.py: support FixedAtBuild PCD
[mirror_edk2.git] / IntelFsp2Pkg / Tools / GenCfgOpt.py
1 ## @ GenCfgOpt.py\r
2 #\r
3 # Copyright (c) 2014 - 2018, Intel Corporation. All rights reserved.<BR>\r
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
14 import os\r
15 import re\r
16 import sys\r
17 import struct\r
18 from   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
60 Copyright (c) %4d, Intel Corporation. All rights reserved.<BR>\r
61 \r
62 Redistribution and use in source and binary forms, with or without modification,\r
63 are 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
91 class 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
288 class CGenCfgOpt:\r
289     def __init__(self):\r
290         self.Debug          = False\r
291         self.Error          = ''\r
292 \r
293         self._GlobalDataDef = """\r
294 GlobalDataDef\r
295     SKUID = 0, "DEFAULT"\r
296 EndGlobalData\r
297 \r
298 """\r
299         self._BuidinOptionTxt = """\r
300 List &EN_DIS\r
301     Selection 0x1 , "Enabled"\r
302     Selection 0x0 , "Disabled"\r
303 EndList\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
312         self._PcdsDict    = {}\r
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
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
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
382     def EvaluateExpress (self, Expr):\r
383         ExpExpr = self.ExpandPcds(Expr)\r
384         ExpExpr = self.ExpandMacros(ExpExpr)\r
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
420     def ParseDscFile (self, DscFile, FvDir):\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         IsDefSect       = False\r
428         IsPcdSect       = False\r
429         IsUpdSect       = False\r
430         IsVpdSect       = False\r
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
446                 IsDefSect = False\r
447                 IsPcdSect = False\r
448                 IsVpdSect = False\r
449                 IsUpdSect = False\r
450                 if  Match.group(1).lower() == "Defines".lower():\r
451                     IsDefSect = True\r
452                 if  (Match.group(1).lower() == "PcdsFeatureFlag".lower() or Match.group(1).lower() == "PcdsFixedAtBuild".lower()):\r
453                     IsPcdSect = True\r
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
466                     IsUpdSect = True\r
467             else:\r
468                 if IsDefSect or IsPcdSect or IsUpdSect or IsVpdSect:\r
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
494                             Match  = re.match("!(if|elseif)\s+(.+)", DscLine.split("#")[0])\r
495                             if Match:\r
496                                 Result = self.EvaluateExpress(Match.group(2))\r
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
518                                         PackagesPath = os.getenv("PACKAGES_PATH")\r
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
527                                         if IncludeDsc == None:\r
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
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
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
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
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
629                     ConfigDict['offset'] = int (Match.group(3), 16)\r
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
680                     # !BSF FIELD:{SerialDebugPortAddress0:1}\r
681                     # or\r
682                     # @Bsf FIELD:{SerialDebugPortAddress0:1b}\r
683                     Match = re.match("^\s*#\s+(!BSF|@Bsf)\s+FIELD:{(.+):(\d+)([Bb])?}", DscLine)\r
684                     if Match:\r
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
693                         SubCfgDict['cname']  = Match.group(2)\r
694                         SubCfgDict['bitlength'] = int (Match.group(3)) * UnitBitLen\r
695                         if SubCfgDict['bitlength'] > 0:\r
696                             LastItem =  self._CfgItemList[-1]\r
697                             if len(LastItem['subreg']) == 0:\r
698                                 SubOffset  = 0\r
699                             else:\r
700                                 SubOffset  = LastItem['subreg'][-1]['bitoffset'] + LastItem['subreg'][-1]['bitlength']\r
701                             SubCfgDict['bitoffset'] = SubOffset\r
702                             LastItem['subreg'].append (SubCfgDict.copy())\r
703                         ConfigDict['name']   = ''\r
704         return Error\r
705 \r
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
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
737                 idx = 0\r
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
743                 valuestr = self.GetBsfBitFields(SubItem, bytearray)\r
744                 SubItem['value'] = valuestr\r
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
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
874             if Name.startswith("UnusedUpdSpace") and Length != 1:\r
875                 IsArray = True\r
876                 Type = "UINT8"\r
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
968            if Match and Match.group(3) == 'END':\r
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
1085                                 Marker = ''\r
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
1094 \r
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
1131             HeaderFd.write("#pragma pack(1)\n\n")\r
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
1178                         HeaderFd.write (Line)\r
1179             HeaderFd.write("#pragma pack()\n\n")\r
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
1190         HeaderFd.write("#pragma pack(1)\n\n")\r
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
1223                         HeaderFd.write (Line)\r
1224         HeaderFd.write("#pragma pack()\n\n")\r
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
1231         LogExpr = CLogicalExpression()\r
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
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
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
1253                     test = LogExpr.getNumber (OpVal)\r
1254                     if test is None:\r
1255                         raise Exception("Selection Index '%s' is not a number" % OpVal)\r
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
1267             BsfFd.write('    %s $%s, "%s", &%s,\n' % (Item['type'], PcdName, Item['name'], Options))\r
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
1272                 BsfFd.write('    EditNum $%s, "%s", %s,\n' % (PcdName, Item['name'], Match.group(1)))\r
1273                 WriteHelp = 2\r
1274         elif Item['type'].startswith("EditText"):\r
1275             BsfFd.write('    %s $%s, "%s",\n' % (Item['type'], PcdName, Item['name']))\r
1276             WriteHelp = 1\r
1277         elif Item['type'] == "Table":\r
1278             Columns = Item['option'].split(',')\r
1279             if len(Columns) != 0:\r
1280                 BsfFd.write('    %s $%s "%s",' % (Item['type'], PcdName, Item['name']))\r
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
1292 \r
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
1299                     BsfFd.write('        Help "%s"\n' % (HelpLine))\r
1300                 else:\r
1301                     BsfFd.write('             "%s"\n' % (HelpLine))\r
1302             if WriteHelp == 2:\r
1303                     BsfFd.write('             "Valid range: %s ~ %s"\n' % (Match.group(2), Match.group(3)))\r
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
1315         BsfFd.write("%s\n" % self._GlobalDataDef)\r
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
1327                     BitsOffset =  NextOffset * 8\r
1328                     for SubItem in Item['subreg']:\r
1329                         BitsOffset += SubItem['bitlength']\r
1330                         if SubItem['name'] == '':\r
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
1335                         else:\r
1336                             Options = self.WriteBsfStruct(BsfFd, SubItem)\r
1337                             if len(Options) > 0:\r
1338                                 OptionDict[SubItem['space']+'_'+SubItem['cname']] = Options\r
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
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
1358         BsfFd.write("%s" % self._BuidinOptionTxt)\r
1359 \r
1360         for Each in OptionDict:\r
1361             BsfFd.write("List &%s\n" % Each)\r
1362             for Item in OptionDict[Each]:\r
1363                 BsfFd.write('    Selection %s , "%s"\n' % (Item[0], Item[1]))\r
1364             BsfFd.write("EndList\n\n")\r
1365 \r
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
1370 \r
1371         for Each in self._CfgPageDict:\r
1372             BsfFd.write('Page "%s"\n' % self._CfgPageDict[Each])\r
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
1389             BsfFd.write("EndPage\n\n")\r
1390 \r
1391         BsfFd.close()\r
1392         return  Error\r
1393 \r
1394 \r
1395 def Usage():\r
1396     print "GenCfgOpt Version 0.52"\r
1397     print "Usage:"\r
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
1401 \r
1402 def 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
1416 \r
1417         OutFile = ''\r
1418         if argc > 4:\r
1419             if sys.argv[4][0] == '-':\r
1420                 Start = 4\r
1421             else:\r
1422                 OutFile = sys.argv[4]\r
1423                 Start = 5\r
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
1428 \r
1429         FvDir = sys.argv[3]\r
1430         if not os.path.exists(FvDir):\r
1431             os.makedirs(FvDir)\r
1432 \r
1433         if GenCfgOpt.ParseDscFile(DscFile, FvDir) != 0:\r
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
1469 if __name__ == '__main__':\r
1470     sys.exit(Main())\r